<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </configSections> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"> <parameters> <parameter value="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True" /> </parameters> </defaultConnectionFactory> </entityFramework> <!-- 连接字符串 --> <connectionStrings> <add name="testDb" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;database=TestDB;AttachDBFilename=E:\Programming\VSProject2010\Linq\EFCodeFirstLogTractingTest\EFCodeFirstLogTractingTest\TestDB.mdf;User Instance=true" providerName="System.Data.SqlClient"/> </connectionStrings> <system.data> <!-- 注册 EF Provider Wrapper --> <DbProviderFactories> <add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" /> <add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" /> </DbProviderFactories> </system.data> </configuration>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations; namespace EFCodeFirstLogTractingTest.Models { [Table("Memo")] public class Memo { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public string Title { get; set; } } }
TestDbEntities.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; namespace EFCodeFirstLogTractingTest.Models { public class TestDbEntities : DbContext { public TestDbEntities() : base("testDb") { } public DbSet<Memo> Memos { get; set; } } }TestDbEntitiesInitializer.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; namespace EFCodeFirstLogTractingTest.Models { public class TestDbEntitiesInitializer : DropCreateDatabaseAlways<TestDbEntities> { protected override void Seed(TestDbEntities context) { base.Seed(context); new List<Memo> { new Memo { Title="memo1" }, new Memo { Title="memo2" }, new Memo { Title="memo3" }, }.ForEach(m => context.Memos.Add(m)); } } }好了,CodeFirst已经可以工作了。
public TestDbEntities() : this("name=testDb") { } public TestDbEntities(string nameOrConnectionString) : base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(nameOrConnectionString), true) { var ctx = ((IObjectContextAdapter)this).ObjectContext; ctx.GetTracingConnection().CommandExecuting += (s, e) => { Console.WriteLine(e.ToTraceString()); }; }看看好使不?Oh NO~ 得到下面的异常:
System.ArgumentException was unhandled HResult=-2147024809 Message=The 'data source' keyword is not supported. Source=System.Data.Entity StackTrace: at System.Data.EntityClient.EntityConnectionStringBuilder.set_Item(String keyword, Object value) at System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(String value) at EFProviderWrapperToolkit.EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(String entityConnectionString, String[] wrapperProviders) ...看了下 EFProviderWrappers 源码,才发现 EFProviderWrappers 只接受一个 EntityConnectionString( MSDN)。搜了下,按照下面的解决方法:
public class EFTracingUtil { public static DbConnection GetConnection(string nameOrConnectionString) { try { // this only supports entity connection strings http://msdn.microsoft.com/en-us/library/cc716756.aspx return EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(nameOrConnectionString); } catch (ArgumentException) { if (nameOrConnectionString.Contains('=')) { nameOrConnectionString = nameOrConnectionString.Substring(nameOrConnectionString.IndexOf('=') + 1); } // an invalid entity connection string is assumed to be a normal connection string name or connection string (Code First) ConnectionStringSettings connectionStringSetting = ConfigurationManager.ConnectionStrings[nameOrConnectionString]; string connectionString; string providerName; if (connectionStringSetting != null) { connectionString = connectionStringSetting.ConnectionString; providerName = connectionStringSetting.ProviderName; } else { providerName = "System.Data.SqlClient"; connectionString = nameOrConnectionString; } return CreateTracingConnection(connectionString, providerName); } } private static EFTracingConnection CreateTracingConnection(string connectionString, string providerInvariantName) { string wrapperConnectionString = String.Format(@"wrappedProvider={0};{1}", providerInvariantName, connectionString); EFTracingConnection connection = new EFTracingConnection { ConnectionString = wrapperConnectionString }; return connection; } }把 TestDbEntities 的构造函数修改为如下:
public TestDbEntities(string nameOrConnectionString) : base(EFTracingUtil.GetConnection(nameOrConnectionString), true) { var ctx = ((IObjectContextAdapter)this).ObjectContext; ctx.GetTracingConnection().CommandExecuting += (s, e) => { Console.WriteLine(e.ToTraceString()); }; }再来试试,Oh Shit 还是有异常!
System.ArgumentException was unhandled HResult=-2147024809 Message=The provider manifest given is not of type 'System.Data.SqlClient.SqlProviderManifest'. Source=System.Data.Entity StackTrace: 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) at System.Data.Objects.ObjectContext.CreateDatabase() ......错误来源很可能是 SqlClient 内部的,它预期得到 SqlProviderManifest 但得到的是 DbProviderManifestWrapper。只好绕道了,通过 Database.SetInitializer 不行... 还好EF 4.3的新特性:数据库迁移。在 Package Manager Console 里:Enable-Migrations
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.其实这个原因是因为我的 TestDbEntities() 无参数的默认构造方法:
public TestDbEntities() : this("name=testDb") { }刚才改为 "name=testDb", 而 Migrations 只认 "testDb" (因为它直接到 config 文件中读取 ConnectionString)
public TestDbEntities() : base("testDb") { }注意:外部使用时如果想要 Tracing 就不能用默认构造方法了,因为它没用注册 CommandExecuting 事件处理。
public Configuration() { var connectionString = ConfigurationManager.ConnectionStrings["TestDb"].ConnectionString; TargetDatabase = new DbConnectionInfo(connectionString, "System.Data.SqlClient"); AutomaticMigrationsEnabled = true; }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; using EFCodeFirstLogTractingTest.Models; using System.Data.Entity.Migrations; namespace EFCodeFirstLogTractingTest { class Program { static void Main(string[] args) { //Database.SetInitializer<TestDbEntities>(new TestDbEntitiesInitializer()); Migrations.Configuration config = new Migrations.Configuration(); var migrator = new DbMigrator(config); migrator.Update(); using (var db = new TestDbEntities("name=testDb")) { var result = db.Memos.OrderBy(m => m.Id).Skip(2).First(); Console.WriteLine(result.Title); } Console.Read(); } } }
利用 Log4Net 就不用说了,可以参看我前面这篇文章。