Ok, I have now tracing implemented in the runtime libraries and in the DQE's. I've defined switches for each DQE, and 3 switches for the ORMSupportClasses: general, statemanagement and persistenceexecution.
I already managed to find several redundant calls in the selfservicing code, for example way too many times calling Validate().
By using the switches you can tweak how verbose you want the output. Statemanagement for example in selfservicing is very verbose, for example if you're fetching a prefetch path with a 1000 rows, you'll get a lot of syncing logs
, ah well, it's for troubleshooting anyway. As there are different switches, a developer can switch on just DQE query reporting for example, or just method enter/exit logs.
I still am amazed why so little people talk about this feature of .NET as IMHO this is one of the killer features of .NET and I have never heard of it in the past 3 years I'm now developing .NET code.
I haven't added a set of trace messages and switches to the generated code yet. It's a lot of work, and I first want to know if people want tracing in the generated code as well. But I assume once people start using the traces the requests for particular trace messages will be popping up soon enough.
The level of information that's provided is massive if you turn on everything. Example:
...
Method Enter: DataAccessAdapterBase.SaveEntity(4)
Active Entity Description:
Entity: UnitTests.Dal.Adapter.EntityClasses.CustomerEntity. ObjectID: 5d746321-8c99-49dd-87cf-f2952ec9bc8b
PrimaryKey field: CustomerId. Type: System.Int32. Value: 0
Method Enter: DataAccessAdapterBase.SaveEntity(4)
Active Entity Description:
Entity: UnitTests.Dal.Adapter.EntityClasses.AddressEntity. ObjectID: c72a772e-6d94-42bb-b3d4-e6aa89ce2425
PrimaryKey field: AddressId. Type: System.Int32. Value: 0
Method Enter: EntityBase2.Validate
Active Entity Description:
Entity: UnitTests.Dal.Adapter.EntityClasses.AddressEntity. ObjectID: c72a772e-6d94-42bb-b3d4-e6aa89ce2425
PrimaryKey field: AddressId. Type: System.Int32. Value: 0
Entity Validation Result: True
Method Exit: EntityBase2.Validate
Method Enter: CreateInsertDQ
Generated Sql query:
Query: INSERT INTO [LLBLGenProUnitTest].[dbo].[Address] ([StreetName],[HouseNumber],[Zipcode],[City],[Country],[TestRunID]) VALUES (@StreetName,@HouseNumber,@Zipcode,@City,@Country,@TestRunId);SELECT @AddressId=SCOPE_IDENTITY()
Parameter: @AddressId : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Output. Value: 0.
Parameter: @StreetName : AnsiString. Length: 100. Precision: 0. Scale: 0. Direction: Input. Value: Zeilstraat.
Parameter: @HouseNumber : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 99.
Parameter: @Zipcode : AnsiStringFixedLength. Length: 10. Precision: 0. Scale: 0. Direction: Input. Value: 2586 RB.
Parameter: @City : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: Den Haag.
Parameter: @Country : AnsiString. Length: 50. Precision: 0. Scale: 0. Direction: Input. Value: Nederland.
Parameter: @TestRunId : Guid. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: f3356b34-5217-4796-8fc6-06570a1da28d.
Method Exit: CreateInsertDQ
Method Enter: DataAccessAdapterBase.ExecuteActionQuery
Method Enter: DataAccessAdapterBase.OpenConnection
Method Exit: DataAccessAdapterBase.OpenConnection
Method Exit: DataAccessAdapterBase.ExecuteActionQuery
Method Enter: Query.ReflectOutputValuesInRelatedFields
Syncing field AddressId with parameter @AddressId.
Method Exit: Query.ReflectOutputValuesInRelatedFields
Method Enter: DataAccessAdapterBase.FetchEntity(1)
Active Entity Description:
Entity: UnitTests.Dal.Adapter.EntityClasses.AddressEntity. ObjectID: c72a772e-6d94-42bb-b3d4-e6aa89ce2425
PrimaryKey field: AddressId. Type: System.Int32. Value: 2729
Method Enter: DataAccessAdapterBase.FetchEntityUsingFilter(3)
Method Enter: CreateSelectDQ (Paging)
Method Enter: CreateSelectDQ
Generated Sql query:
Query: SELECT [LLBLGenProUnitTest].[dbo].[Address].[AddressID] AS [AddressId],[LLBLGenProUnitTest].[dbo].[Address].[StreetName] AS [StreetName],[LLBLGenProUnitTest].[dbo].[Address].[HouseNumber] AS [HouseNumber],[LLBLGenProUnitTest].[dbo].[Address].[Zipcode] AS [Zipcode],[LLBLGenProUnitTest].[dbo].[Address].[City] AS [City],[LLBLGenProUnitTest].[dbo].[Address].[Country] AS [Country],[LLBLGenProUnitTest].[dbo].[Address].[TestRunID] AS [TestRunId] FROM [LLBLGenProUnitTest].[dbo].[Address] WHERE ( [LLBLGenProUnitTest].[dbo].[Address].[AddressID] = @AddressId1)
Parameter: @AddressId1 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 2729.
Method Exit: CreateSelectDQ
Method Exit: CreateSelectDQ (Paging): no paging.
Method Enter: DataAccessAdapterBase.ExecuteSingleRowRetrievalQuery
Method Enter: DataAccessAdapterBase.OpenConnection
Method Exit: DataAccessAdapterBase.OpenConnection
Method Enter: DataAccessAdapterBase.FetchOneRow
Method Enter: DataAccessAdapterBase.ReadRowIntoFields
Method Exit: DataAccessAdapterBase.ReadRowIntoFields
Method Exit: DataAccessAdapterBase.FetchOneRow
Method Exit: DataAccessAdapterBase.ExecuteSingleRowRetrievalQuery
Method Exit: DataAccessAdapterBase.FetchEntityUsingFilter
Method Exit: DataAccessAdapterBase.FetchEntity(1)
Method Enter: EntityBase2.SyncFKFields
Active Entity Description:
Entity: UnitTests.Dal.Adapter.EntityClasses.CustomerEntity. ObjectID: 5d746321-8c99-49dd-87cf-f2952ec9bc8b
PrimaryKey field: CustomerId. Type: System.Int32. Value: 0
Data Supplying Entity Description:
Entity: UnitTests.Dal.Adapter.EntityClasses.AddressEntity. ObjectID: 5d746321-8c99-49dd-87cf-f2952ec9bc8b
PrimaryKey field: AddressId. Type: System.Int32. Value: 2729
Syncing FK field VisitingAddressId with PK field AddressId
Method Exit: EntityBase2.SyncFKFields
Method Exit: DataAccessAdapterBase.SaveEntity(4)
Method Enter: DataAccessAdapterBase.SaveEntity(4)
...
Needless to say, I'm very very happy with it, and it's a massive gain for all customers.
Tracing is setup easily in the .config file of your app:
...
<system.diagnostics>
<switches>
<add name="SqlServerDQE" value="4" />
<add name="AccessDQE" value="4" />
<add name="OracleDQE" value="0" />
<add name="FirebirdDQE" value="0" />
<add name="MySqlDQE" value="0" />
<add name="DB2DQE" value="0" />
<add name="ORMGeneral" value="4" />
<add name="ORMStateManagement" value="4" />
<add name="ORMPersistenceExecution" value="4" />
</switches>
</system.diagnostics>
...
I don't define any trace listeners there, but you can by just adding a few lines to the system.diagnostics section, catch all reported messages by the textwriter listener, which writes it all to the file you specify. Or define your own for example. If you don't define any trace listeners, you'll see the output of the app you're running in the vs.net output window (if you've started the app in vs.net using (cntrl-)f5.
Tracing is available in SelfServicing and Adapter.