How to Make Tracing and Caching Providers Work for EF 4.1 Code First

Posted by Hugh Ang at 12/21/2011 09:08:00 PM

The tracing and caching providers (or here) provide an excellent way to trace and cache EF queries. Unlike those that attempt to do the same above the EF API, these providers work under the covers and make tracing and caching non-invasive for the application code. Specifically, for cases where entities are lazy-loaded via EF and those entities are to be cached, this caching provider is truly more advantageous.

However, these providers were written before EF 4.1 code first and they wouldn't work if you just follow the old sample. Luckily, it is not too difficult to make them work. The trick is to create a wrapping EFCachingConnection or EFTracingConnection that wraps a DbConnection (such as SqlConnection) and pass it to the DbContext constructor. I will just demonstrate the caching related code here but you should be able to chain tracing, caching and then the underlying SqlConnection using the same pattern.

First, a minor modification to the EFCachingConnection constructor is needed. As shown in the following code, we need to be able to set the wrappedProviderInvariantName via the ctor:




  1.  

  2. public EFCachingConnection(DbConnection wrappedConnection, string wrappedProviderInvariantName)

  3. {

  4. this.WrappedConnection = wrappedConnection;

  5. this.CachingPolicy = EFCachingProviderConfiguration.DefaultCachingPolicy;

  6. this.Cache = EFCachingProviderConfiguration.DefaultCache;

  7. base.wrappedProviderInvariantName = wrappedProviderInvariantName; // make it possible to set the wrappedProviderInvariantName via this ctor

  8. }





The I use the following helper function to create an instance of the EFCachingConnection that wraps a SqlConnection:




  1.  

  2. public static EFCachingConnection CreateEFCachingConnectionWrapper(string nameOrConnectionString)

  3. {

  4. string connectionString;

  5. if (nameOrConnectionString.Contains("="))

  6. connectionString = nameOrConnectionString;

  7. else

  8. connectionString = ConfigurationManager.ConnectionStrings[nameOrConnectionString].ConnectionString;


  9. DbConnection connection = new SqlConnection(connectionString);

  10.  

  11. return new EFCachingConnection(connection, "System.Data.SqlClient");

  12. }





Now you would simply pass the newly constucted EFCachingConnection instance to the ctor of DbContext:




  1.  

  2. public MyContext(DbConnection connection)

  3. : base(connection, true)

  4. {





Note that MyContext is the application's EF code first context, which derives from DbContext and has probably overriden the OnModelCreating() method.

Last and not the least you would need to call EFCachingProviderConfiguration.RegisterProvider() first when you start your application.

Happy holidays and happy EF coding!

6 comments:

juangdiaz said...

can you post a full sample code, i would appreciate it:)

Hugh Ang said...

juangdiaz, I cannot post client project code unfortunately. Let me know where you are stuck and if I can help.

Anonymous said...

Your suggestions for getting the caching provider to function in code-first worked, so thx for that.

However, you mention:

"you should be able to chain tracing, caching and then the underlying SqlConnection using the same pattern"

I haven't been able to get this work by making simple changes to the provider code. I suspect this would require more indepth changes to the Provider code. Could you provide an example of how to make this work so that we can use both the caching and tracing providers at the same time?

Anonymous said...

Your suggestions for getting the caching provider to function in code-first worked, so thx for that.

However, you mention:

"you should be able to chain tracing, caching and then the underlying SqlConnection using the same pattern"

I haven't been able to get this work. I suspect this would require more indepth changes to the Provider code. Could you provide an example of how to make this work so that we can use both the caching and tracing providers at the same time?

Hugh Ang said...

Let me know what problem you were having. Did you try wrap EFCachingConnection inside EFTracingConnection or the other way around?

Yahav Gindi Bar said...

Just in case somebody interest - I've been able to chain these two providers.

Code:

public static DbConnection CreateEFCachingConnectionWrapper(string nameOrConnectionString)
{
string connectionString;

if (nameOrConnectionString.Contains("="))
connectionString = nameOrConnectionString;
else
connectionString = ConfigurationManager.ConnectionStrings[nameOrConnectionString].ConnectionString;

DbConnection connection = new System.Data.SqlClient.SqlConnection(connectionString);

return new EFCachingConnection(new EFTracingConnection(connection, "System.Data.SqlClient"), "EFTracingProvider");
}

Note that the EFCachingProvider MUST WRAP the EFTracingProvider otherwise it won't work.