none
EF CTP5 Code First DatabaseInitializer and EFTracingConnection

    Question

  • I am trying to use Jarek Kowalski's EFTracingConnection wrapper (http://code.msdn.microsoft.com/EFProviderWrappers) to get tracing of generated t-sql using EF CTP5 Code First. I got it working as long as I set

                DbDatabase.SetInitializer<MyContainer>(null);

    As Jarek mentioned here http://jkowalski.com/2010/04/23/logging-sql-statements-in-entity-frameworkcode-first/ a limitation is that the wrapper does not work with database creation with the SqlClient provider (Jarek uses a ObjectContext in his example. I use a DbContext). If I use a database initializer I get a System.ArgumentException "The provider manifest given is not of type 'System.Data.SqlClient.SqlProviderManifest'." with the following stack trace

       at System.Data.SqlClient.SqlProviderServices.GetSqlVersion(StoreItemCollection storeItemCollection)
       at System.Data.SqlClient.SqlProviderServices.DbCreateDatabase(DbConnection connection, Nullable`1 commandTimeout, StoreItemCollection storeItemCollection)
       at System.Data.Common.DbProviderServices.CreateDatabase(DbConnection connection, Nullable`1 commandTimeout, StoreItemCollection storeItemCollection)
       at EFProviderWrapperToolkit.DbProviderServicesBase.DbCreateDatabase(DbConnection connection, Nullable`1 commandTimeout, StoreItemCollection storeItemCollection) in C:\Projects\EF4ProviderWrappers\EFProviderWrapperToolkit\DbProviderServicesBase.cs:line 143

    So, if I want to use a database initializer, I use an unwrapped connection. In my case in Glabal.asax.cs

                DbDatabase.SetInitializer<MyContainer>(new DatabaseInitializer());

                using (MyContainer context = new MyContainer())
                {
                    context.Database.Initialize(false);
                }         

     However, if I then want to use the EFTracingConnection (in my case in a RIA Services DomainService) after the database initializer has run, I get a System.NotSupportedException "Using the same DbModel to create contexts against different types of database servers is not supported. Instead, create a separate DbModel for each type of server being used." with the following stack trace

       at System.Data.Entity.Internal.CodeFirstCachedMetadataWorkspace.GetMetadataWorkspace(DbConnection connection)
       at System.Data.Entity.Infrastructure.DbModel.CreateObjectContext[TContext](DbConnection existingConnection)
       at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
       at System.Data.Entity.Internal.InternalContext.Initialize()
       at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
       at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
       at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator()
       at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.IEnumerable.GetEnumerator()
       at System.ServiceModel.DomainServices.Server.DomainService.Enumerate[T](IEnumerable enumerable, Int32 estimatedResultCount)
       at System.ServiceModel.DomainServices.Server.DomainService.Query(QueryDescription queryDescription, IEnumerable`1& validationErrors, Int32& totalCount)

    This was not a problem in Jarek's example where he uses an ObjectContext with Code First, but it is a problem when I use a DbContext and a database initializer .Just because I use an unwrapped connection first and then a wrapped connection, EF Code First CTP5 thinks I am using the same model against different database servers, but of course it is the same database server. As mentioned it works fine as long as I dont use a database initializer and therefore only use the wrapped connection. I have tried setting

                DbDatabase.SetInitializer<MyContainer>(null);

    again after the code in the Global.asax.cs, but that made no difference. Has anybody else managed to get the EFTracingConnection working with Code First and a database initializer?  

    kind regards

    Remco

    Thursday, December 23, 2010 1:00 PM

All replies

  • Remco,

     

    I don’t think that you will be able to use database initializers with Jarek’s wrapping provider since it doesn’t support the necessary parts of the provider API.  Also, EF identifies the type of database it is being used against by the provider type and information from that provider—this is by design and is unlikely to change.  The internal caching that Code First for the compiled model is bound to the provider/type of database being used because the model itself, when compiled, is bound to the provider.  However, you can perform your own caching instead—this thread has some info on how to do that: http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/fb3eaba4-d12c-4eb5-b9c1-4acacd2fff3c/. You could then create a model bound to the regular SQL client provider and use this for database creation, etc, and create a separate model (from the same ModelBuilder) that is bound to Jarek’s provider for the rest of your app.  This is obviously more complicated than using the internal caching, but is likely to be your best bet for getting something working unless you can get Jarek to update his code to support Code First.

     

    Thanks,

    Arthur

    Friday, December 24, 2010 1:46 AM
    Moderator