日期:2014-05-20  浏览次数:21287 次

ADO.NET Entity Framework CodeFirst 如何输出日志(EF4.3)
之前写过一篇如何利用 EFProviderWrappers 在EF中增加日志的blog,那篇文章是基于 ModelFirst 来写的,这里在 EF 4.3 CodeFirst 上再次实现。

1. 事前准备
下载 EFProviderWrappers 程序集(点击此处下载),添加:EFProviderWrapperToolkit.dll,EFTracingProvider.dll 引用。
并通过 NuGet 添加 EntityFramework 4.3, Log4Net。

App.config中添加连接字符串,注册 EFProviderWrappers
直接添加了一个空mdf文件(TestDB.mdf)作为Database,注意 CodeFirst 中连接字符串为普通的ADO.NET数据库连接字符串。ModelFirst中则是EntityConnectionString,而这一点也成为后面的一个小障碍。

2. 添加 Model, Entities, EntitiesInitializer
实体:Memo.cs

TestDbEntities.cs

TestDbEntitiesInitializer.cs
它负责初始化数据库,添加3条数据。
好了,CodeFirst已经可以工作了。

3. 添加 EFProviderWrappers
前面的经验告诉我,EFTracingProvider 通过扩展方法为 ObjectContext 添加了 GetTractingConnection(),TracingConnection里的 CommandExecuting 事件正是我们需要监听 Linq 转化成真正 SQL 的时机。
于是,我将上面的 TestDbEntities.cs 修改为如下,这样执行 Linq2EF 语句时,就能在控制台输出实际的SQL了。
(注意:此时 nameOrConnectionString 传入的是 name=testDb 而不是 testDb)
看看好使不?Oh NO~ 得到下面的异常:
看了下 EFProviderWrappers 源码,才发现 EFProviderWrappers 只接受一个 EntityConnectionString(MSDN)。搜了下,按照下面的解决方法:
添加一个 EFTracingUtil 类:(别忘记添加 System.Configuration.dll)
把 TestDbEntities 的构造函数修改为如下:
再来试试,Oh Shit 还是有异常!
错误来源很可能是 SqlClient 内部的,它预期得到 SqlProviderManifest 但得到的是 DbProviderManifestWrapper。只好绕道了,通过 Database.SetInitializer 不行... 还好EF 4.3的新特性:数据库迁移。在 Package Manager Console 里:Enable-Migrations
运行命令还是会得到下面的错误:
其实这个原因是因为我的 TestDbEntities() 无参数的默认构造方法:
刚才改为 "name=testDb", 而 Migrations 只认 "testDb" (因为它直接到 config 文件中读取 ConnectionString)
解决方法有两个:
(1) 改回去,将默认的构造方法修改为:
注意:外部使用时如果想要 Tracing 就不能用默认构造方法了,因为它没用注册 CommandExecuting 事件处理。
(2) 修改 Migrations.Config 里的 TargetDatabase,这里是允许开发者直接修改它来实现各种复杂的数据迁移的。

这里还是用了方法(1),那么最后的使用如下:


利用 Log4Net 就不用说了,可以参看我前面这篇文章。