Jarek Kowalski's Provider 提供了Entity Framework的二级缓存处理与SQL语句日志监控功能,但是Code First 模式下却无法工作。几经周折终于找到了在CodeFirst下使用它的两种方法,记录一下过程,免得忘记了.
1、直接使用 EFTracingConnection 或EFCachingConnection
google 搜了一下找到了原作者的一篇文章:《Logging SQL statements in Entity Framework/Code First》 ,看来历史很悠久了居然是Feature CTP 3 的,源码与EF4.1差距非常大。但是作者已经给出了思路:EFCodeFirst可以直接使用System.Data.SqlClient 等数据提供程序。我们以MVCMusicStore 为实例进行改造。
首先查看DbContext的构造函数:
protected DbContext();
protected DbContext(DbCompiledModel model);
public DbContext(string nameOrConnectionString);
public DbContext(DbConnection existingConnection, bool contextOwnsConnection);
public DbContext(ObjectContext objectContext, bool dbContextOwnsObjectContext);
public DbContext(string nameOrConnectionString, DbCompiledModel model);
public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection);
关键就是黄色哪行了,由于EFTracingProvider和EFCachingProvider 只是使用了包装模式, 它使用装饰模式和抽象工厂,直接继承了以下ADO.NET核心对象:DbConnection、DbCommand、DbCommandDefinition、DbProviderFactoryBase、DbProviderServicesBase,并命名为***Wrapper。以下为DbConnection的扩展:
引用自:《数据层扩展包EFCachingProvider 总结》
我们可以使用public DbContext(DbConnection existingConnection, bool contextOwnsConnection); 构造函数将DbCachingConnection或DbTraceConnection传入DbContext,改造MusicStoreEntities的构造函数:
public class MusicStoreEntities : DbContext
{
public MusicStoreEntities(DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{
}
public MusicStoreEntities():base()
{
}
public DbSet<Album> Albums { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<Cart> Carts { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
}
然后创建一个DBContextFactory工厂类,添加如下方法
private EFCachingConnection CreateCachingConnection()
{
var connection = new EFCachingConnection
{
ConnectionString = @"wrappedProvider=" + this.ProviderInvariantName + ";" + this.ConnectionString
};
// set up an event which will be raised whenever command has finished executing
connection.Cache = new AspNetCache();
connection.CachingPolicy = CachingPolicy.CacheAll;
return connection;
}
/// <summary>
/// 创建MusicStoreEntities实例
/// </summary>
public MusicStoreEntities CreateContext()
{
return new MusicStoreEntities(this.CreateCachingConnection(), true);
}
调用代码:
var factory = new DBContextFactory( "System.Data.SqlClient", @"Data Source=.;Initial Catalog=Music;Persist Security Info=True;User ID=sa;Password=123456");
var context= factory.CreateContext();
本以为到这里就算万事大吉了,程序运行时却曝出错误:“给定的提供程序清单不是“System.Data.SqlClient.SqlProviderManifest”类型”。 Google一番后发现一老外跟我遇见差不多的错误:《EF CTP5 Code First DatabaseInitializer and EFTracingConnection》http://social.msdn.microsoft.com/Forums/en/adonetefx/thread/a501e2c7-d31d-460a-80e5-4d2efc96ca6b,看来上面的提供程序实现的不够完美,所以还得想想补救措施了,这个作者给了一个思路就是在数据库初始化的时候使用使用原始的构造函数,照葫芦画瓢写了一下
System.Data.Entity.Database.SetInitializer(new MvcMusicStore.Models.SampleData()); using (var db = new MusicStoreEntities()) { db.Database.Initialize(false); }
把上面代码加到 Glabal.asax 文件中
正常运行啦!