俗話說:“工欲善其事必先利其器”,在深入講解Entity Framework之前,先準(zhǔn)備一下開發(fā)工具以及前期的配置。
一、開發(fā)工具
開發(fā)工具基本略過,這里說一下,我使用的是Visual Studio 2012,Entity Framework版本為4.3.1,獲取這個版本的辦法:在Package Manager Console中輸入Install-Package EntityFramework -Version 4.3.1。至于數(shù)據(jù)庫,主要是LocalDb。
二、連接數(shù)據(jù)庫
當(dāng)使用NuGet安裝完Entity Framework后,在配置文件中會自動加入entityFramework節(jié),里面有defaultConnectionFactory元素,如下:
1: <?xml version="1.0" encoding="utf-8"?>
2: <configuration>
3: <configSections>
4: <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
5: <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
6: </configSections>
7: <entityFramework>
8: <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
9: <parameters>
10: <parameter value="Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=True" />
11: </parameters>
12: </defaultConnectionFactory>
13: </entityFramework>
14: </configuration>
在沒有提供具體數(shù)據(jù)庫連接的情況下,EF默認使用這一配置。如上面代碼中,默認會連接到LocalDb,數(shù)據(jù)庫的名稱為上下文完全限定名(命名空間+類名)。以前經(jīng)常提到默認連接到.\SQLEXPRESS,因為安裝的版本不同。
EF中提供了兩個連接工廠:SqlConnectionFactory和SqlCeConnectionFactory。使用方式分別如下:
1: Database.DefaultConnectionFactory = new SqlConnectionFactory("Data Source=.;Database=Test;UId=sa;Pwd=sasa;MultipleActiveResultSets=True");
或
1: Database.DefaultConnectionFactory = new SqlConnectionFactory("Data Source=.;Database=Test;User=sa;Password=sasa;MultipleActiveResultSets=True");
和
1: Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
在配置文件和代碼中同時有DefaultConnectionFactory的情況下,代碼中的優(yōu)先。
下面,寫一個簡單的控制臺程序。代碼如下:
1: namespace ConnectDatabase
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: using (TestContext ctx = new TestContext())
8: {
9: var blog = new Blog()
10: {
11: Name = "EF"
12: };
13: blog.Posts.Add(new Post()
14: {
15: Title = "連接數(shù)據(jù)庫",
16: Content = "這是連接數(shù)據(jù)庫的測試",
17: Creationdate = DateTime.Now,
18: Blog = blog
19: });
20: ctx.Blogs.Add(blog);
21: ctx.SaveChanges();
22:
23: foreach (var item in ctx.Blogs)
24: {
25: Console.WriteLine(item.Name);
26: }
27: }
28: }
29: }
30:
31: public class TestContext : DbContext
32: {
33: protected override void OnModelCreating(DbModelBuilder modelBuilder)
34: {
35: base.OnModelCreating(modelBuilder);
36: }
37:
38: public DbSet<Blog> Blogs { get; set; }
39: public DbSet<Post> Posts { get; set; }
40: }
41:
42: public class Blog
43: {
44: public Blog()
45: {
46: Posts = new List<Post>();
47: }
48:
49: public int Id { get; set; }
50: public string Name { get; set; }
51: public virtual List<Post> Posts { get; set; }
52: }
53:
54: public class Post
55: {
56: public int Id { get; set; }
57: public string Title { get; set; }
58: public string Content { get; set; }
59: public DateTime Creationdate { get; set; }
60: public virtual Blog Blog { get; set; }
61: }
62: }
使用默認連接配置,生成的數(shù)據(jù)庫名稱為:ConnectDatabase.TestContext,如下圖所示:
重寫上面配置有以下方法:
1.在配置文件中添加connectionStrings,name和上下文類名一致。
1: <connectionStrings>
2: <add name="TestContext1" connectionString="Data Source=(localdb)\v11.0;Database=Test;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
3: </connectionStrings>
2.同1,但是name和上下文類名不一致。這就需要修改TextContext代碼,如下:
1: public TestContext() : this("TestContext1") { }
2:
3: public TestContext(string nameOrConnectionString)
4: : base(nameOrConnectionString)
5: {
6:
7: }
或
1: public TestContext()
2: : base("name=TestContext1")
3: {
4:
5: }
或
1: public TestContext():base("TestContext1"){}
下面給出連接具體數(shù)據(jù)庫的配置:
1.連接Sql Server數(shù)據(jù)庫
1: <connectionStrings>
2: <add name="TestContext" connectionString="Data Source=.;Database=Test;User=sa;Password=sasa;MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
3: </connectionStrings>
2.連接Sql Server Compact 4.0
1: <connectionStrings>
2: <add name="TestContext" connectionString="Data Source=|DataDirectory|\Test.sdf" providerName="System.Data.SqlServerCe.4.0"/>
3: </connectionStrings>
3.連接MySql 5.5
連接MySql數(shù)據(jù)庫需要安裝mysql提供程序mysql-connector-net-6.6.4,本文最后提供這些工具的下載地址。
1: <connectionStrings>
2: <add name="TestContext"
3: connectionString="User Id=root;server=localhost;password=sasa;database=test1"
4: providerName="MySql.Data.MySqlClient" />
5: </connectionStrings>
三、數(shù)據(jù)庫初始化
1.關(guān)閉初始化
1: Database.SetInitializer<TestContext>(null);
2.CreateDatabaseIfNotExists
這是Entity Framework的默認初始化策略,沒有必要設(shè)置它,如果真的需要設(shè)置,如下:
1: Database.SetInitializer(new CreateDatabaseIfNotExists<TestContext>());
3.DropCreateDatabaseWhenModelChanges
如果模型發(fā)生了改變,則刪除并重建數(shù)據(jù)庫。
1: Database.SetInitializer(new CreateDatabaseIfNotExists<TestContext>());
4.DropCreateDatabaseAlways
無論模型和數(shù)據(jù)庫匹配與否,都刪除并重建數(shù)據(jù)庫。
1: Database.SetInitializer(new DropCreateDatabaseAlways<TestContext>());
5.Database.Initialize可以強制初始化,即使在當(dāng)前AppDomain中已經(jīng)發(fā)生了。下面我寫個單元測試程序,來演示這一點:
1: [TestClass]
2: public class UnitTest1
3: {
4: [TestMethod]
5: public void TestForceInitialize()
6: {
7: //說明一點:我Demo中的TestContext和Microsoft.VisualStudio.TestTools.UnitTesting.TestContext沖突了,所以寫成了ConnectDatabase.TestContext
8: //Arrage
9: Database.SetInitializer(new DropCreateDatabaseAlways<ConnectDatabase.TestContext>());
10: //Act
11: using (ConnectDatabase.TestContext ctx = new ConnectDatabase.TestContext())
12: {
13: ctx.Database.Initialize(force: true);
14: ctx.Blogs.Add(new ConnectDatabase.Blog()
15: {
16: Name = "強制初始化1"
17: });
18: ctx.SaveChanges();
19: }
20: using (ConnectDatabase.TestContext ctx = new ConnectDatabase.TestContext())
21: {
22: ctx.Database.Initialize(force: true);
23: ctx.Blogs.Add(new ConnectDatabase.Blog()
24: {
25: Name = "強制初始化2"
26: });
27: ctx.SaveChanges();
28: }
29: ConnectDatabase.Blog blog = null;
30: using (ConnectDatabase.TestContext ctx = new ConnectDatabase.TestContext())
31: {
32: blog = ctx.Blogs.FirstOrDefault();
33: }
34:
35: //Assert
36: Assert.IsNotNull(blog);
37: Assert.AreEqual("強制初始化2", blog.Name);
38:
39: }
40: }
測試結(jié)果:
因為設(shè)置的初始化策略為DropCreateDatabaseAlways,每一次調(diào)用Database.Initialize,參數(shù)為true,都會重新刪除并創(chuàng)建數(shù)據(jù)庫。
四、Seed數(shù)據(jù)
創(chuàng)建數(shù)據(jù)庫時初始化一些數(shù)據(jù),首先自定義初始化策略,重寫Seed方法,代碼如下:
1: public class DropCreateDatabaseWithSeedData : DropCreateDatabaseAlways<TestContext>
2: {
3: protected override void Seed(TestContext context)
4: {
5: context.Blogs.Add(new Blog()
6: {
7: Name = "種子數(shù)據(jù)1"
8: });
9: context.Blogs.Add(new Blog()
10: {
11: Name = "種子數(shù)據(jù)2"
12: });
13: //注意沒有調(diào)用context.SaveChanges(),base.Seed(context)會調(diào)用
14: base.Seed(context);
15: }
16: }
下面是測試程序:
1: [TestMethod]
2: public void SeedData()
3: {
4: Database.SetInitializer(new DropCreateDatabaseWithSeedData());
5: List<ConnectDatabase.Blog> blogList = null;
6: using (ConnectDatabase.TestContext ctx = new ConnectDatabase.TestContext())
7: {
8: blogList = ctx.Blogs.OrderBy(t => t.Id).ToList();
9: }
10: Assert.AreEqual(2, blogList.Count);
11: Assert.AreEqual("種子數(shù)據(jù)1", blogList[0].Name);
12: Assert.AreEqual("種子數(shù)據(jù)2", blogList[1].Name);
13: }
測試結(jié)果:
五、創(chuàng)建索引
在Seed方法中,使用ExecuteSqlCommand創(chuàng)建索引,代碼如下:
1: protected override void Seed(TestContext context)
2: {
3: context.Database.ExecuteSqlCommand("CREATE INDEX IX_Test_Name ON Blogs (Name)");
4: context.Blogs.Add(new Blog()
5: {
6: Name = "種子數(shù)據(jù)1"
7: });
8: context.Blogs.Add(new Blog()
9: {
10: Name = "種子數(shù)據(jù)2"
11: });
12: //注意沒有調(diào)用context.SaveChanges(),base.Seed(context)會調(diào)用
13: base.Seed(context);
14: }
六、MySQL相關(guān)
mysql相關(guān)工具下載地址: