Entity Framework如何使用Code First模式管理数据库(code,entity,framework,开发技术)

时间:2024-05-04 21:06:39 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

一、管理数据库连接

1、使用配置文件管理连接之约定

在数据库上下文类中,如果我们只继承了无参数的DbContext,并且在配置文件中创建了和数据库上下文类同名的连接字符串,那么EF会使用该连接字符串自动计算出数据库的位置和数据库名。比如,我们的数据库上下文定义如下:

usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Entity;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceConventionConfigure.EF{///<summary>///继承无参数的DbContext///</summary>publicclassSampleDbEntities:DbContext{publicSampleDbEntities(){//数据库不存在时创建数据库Database.CreateIfNotExists();}}}

在配置文件中定义的连接字符串如下:

<connectionStrings><addname="SampleDbEntities"connectionString="DataSource=.;InitialCatalog=TestDb;IntegratedSecurity=True;MultipleActiveResultSets=True"providerName="System.Data.SqlClient"/></connectionStrings>

定义的连接字符串中name的value值和创建的数据库上下文类的类名相同,这样EF会使用该连接字符串执行数据库操作,究竟会发生什么呢?

运行程序,Program类定义如下:

usingConventionConfigure.EF;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceConventionConfigure{classProgram{staticvoidMain(string[]args){using(varcontext=newSampleDbEntities()){}Console.WriteLine("创建成功");Console.ReadKey();}}}

当运行应用程序时,EF会寻找我们的数据库上下文类,即“SampleDbEntities”,并在配置文件中寻找和它同名的连接字符串,然后它会使用该连接字符串计算出应该使用哪个数据库provider,之后检查数据库位置,之后会在指定的位置创建一个名为TestDb.mdf的数据库文件,同时根据连接字符串的Initial Catalog属性创建了一个名为TestDb的数据库。创建的数据库结构如下:

Entity Framework如何使用Code First模式管理数据库

查看创建后的数据库,会发现只有一张迁移记录表。

2、使用已经存在的ConnectionString

如果我们已经有了一个定义数据库位置和名称的ConnectionString,并且我们想在数据库上下文类中使用这个连接字符串,连接字符串如下:

<connectionStrings><addname="AppConnection"connectionString="DataSource=.;InitialCatalog=TestDb;IntegratedSecurity=True;MultipleActiveResultSets=True"providerName="System.Data.SqlClient"/></connectionStrings>

以上面创建的数据库TestDb作为已经存在的数据库,新添加实体类Student,使用已经存在的ConnectionString查询数据库的Student表,Student实体类定义如下:

usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel.DataAnnotations.Schema;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceExistsConnectionString.Model{[Table("Student")]publicclassStudent{publicintId{get;set;}publicstringName{get;set;}publicstringSex{get;set;}publicintAge{get;set;}}}

我们将该连接字符串的名字传入数据库上下文DbContext的有参构造函数中,数据库上下文类定义如下:

usingExistsConnectionString.Model;usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Entity;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceExistsConnectionString.EF{publicclassSampleDbEntities:DbContext{publicSampleDbEntities():base("name=AppConnection"){}//添加到数据上下文中publicvirtualDbSet<Student>Students{get;set;}}}

上面的代码将连接字符串的名字传给了DbContext类的有参构造函数,这样一来,我们的数据库上下文就会开始使用该连接字符串了,在Program类中输出Name和Age字段的值:

usingExistsConnectionString.EF;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceExistsConnectionString{classProgram{staticvoidMain(string[]args){using(varcontext=newSampleDbEntities()){foreach(varitemincontext.Students){Console.WriteLine("姓名:"+item.Name+""+"年龄:"+item.Age);}}}}}

运行程序,发现会报下面的错误:

Entity Framework如何使用Code First模式管理数据库

出现上面报错的原因是因为数据库上下文发生了改变,与现有数据库不匹配。解决方案:

把数据库里面的迁移记录表删掉或者重命名即可。

重新运行程序,结果如下:

Entity Framework如何使用Code First模式管理数据库

注意:如果在配置文件中还有一个和数据库上下文类名同名的ConnectionString,那么就会使用这个同名的连接字符串。无论我们对传入的连接字符串名称如何改变,都是无济于事的,也就是说和数据库上下文类名同名的连接字符串优先权更大。(即约定大于配置)

3、使用已经存在的连接

通常在一些老项目中,我们只会在项目中的某个部分使用EF Code First,同时,我们想对数据上下文类使用已经存在的数据库连接,如果要实现这个,可将连接对象传给DbContext类的构造函数,数据上下文定义如下:

usingExistsDbConnection.Model;usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Common;usingSystem.Data.Entity;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceExistsDbConnection.EF{publicclassSampleDbEntities:DbContext{publicSampleDbEntities(DbConnectioncon):base(con,contextOwnsConnection:false){}publicvirtualDbSet<Student>Students{get;set;}}}

这里要注意一下contextOwnsConnection参数,之所以将它作为false传入到上下文,是因为它是从外部传入的,当上下文超出了范围时,可能会有人想要使用该连接。如果传入true的话,那么一旦上下文出了范围,数据库连接就会立即关闭。

Program类定义如下:

usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Common;usingSystem.Data.SqlClient;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Configuration;usingExistsDbConnection.EF;namespaceExistsDbConnection{classProgram{staticvoidMain(string[]args){//读取连接字符串stringconn=ConfigurationManager.ConnectionStrings["AppConnection"].ConnectionString;//DbConnection是抽象类,不能直接实例化,声明子类指向父类对象DbConnectioncon=newSqlConnection(conn);using(varcontext=newSampleDbEntities(con)){foreach(varitemincontext.Students){Console.WriteLine("姓名:"+item.Name+""+"年龄:"+item.Age);}}Console.WriteLine("读取完成");Console.ReadKey();}}}

运行程序,结果如下:

Entity Framework如何使用Code First模式管理数据库

二、管理数据库创建

首次运行EF Code First应用时,EF会做下面的这些事情:
1、检查正在使用的DbContext类。
2、找到该上下文类使用的connectionString。
3、找到领域实体并提取模式相关的信息。
4、创建数据库。
5、将数据插入系统。

一旦模式信息提取出来,EF会使用数据库初始化器将该模式信息推送给数据库。数据库初始化器有很多可能的策略,EF默认的策略是如果数据库不存在,那么就重新创建;如果存在的话就使用当前存在的数据库。当然,我们有时也可能需要覆盖默认的策略,可能用到的数据库初始化策略如下:

CreateDatabaseIfNotExists:CreateDatabaseIfNotExists:顾名思义,如果数据库不存在,那么就重新创建,否则就使用现有的数据库。如果从领域模型中提取到的模式信息和实际的数据库模式不匹配,那么就会抛出异常。

DropCreateDatabaseAlways:如果使用了该策略,那么每次运行程序时,数据库都会被销毁。这在开发周期的早期阶段通常很有用(比如设计领域实体时),从单元测试的角度也很有用。

DropCreateDatabaseIfModelChanges:这个策略的意思就是说,如果领域模型发生了变化(具体而言,从领域实体提取出来的模式信息和实际的数据库模式信息失配时),就会销毁以前的数据库(如果存在的话),并创建新的数据库。

MigrateDatabaseToLatestVersion:如果使用了该初始化器,那么无论什么时候更新实体模型,EF都会自动地更新数据库模式。这里很重要的一点是:这种策略更新数据库模式不会丢失数据,或者是在已有的数据库中更新已存在的数据库对象。MigrateDatabaseToLatestVersion初始化器只有从EF4.3才可用。

1、设置初始化策略

EF默认使用CreateDatabaseIfNotExists作为默认初始化器,如果要覆盖这个策略,那么需要在DbContext类中的构造函数中使用Database.SetInitializer方法,下面的例子使用DropCreateDatabaseIfModelChanges策略覆盖默认的策略。数据库上下文类定义如下:

usingInitializationStrategy.Model;usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Entity;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationStrategy.EF{publicclassSampleDbEntities:DbContext{publicSampleDbEntities():base("name=AppConnection"){//使用DropCreateDatabaseIfModelChanges策略覆盖默认的策略Database.SetInitializer<SampleDbEntities>(newDropCreateDatabaseIfModelChanges<SampleDbEntities>());}//添加到数据上下文中publicvirtualDbSet<Student>Students{get;set;}}}

这样一来,无论什么时候创建上下文类,Database.SetInitializer()方法都会被调用,并且将数据库初始化策略设置为DropCreateDatabaseIfModelChanges。

Student领域实体类新增加Email和Address两个属性:

usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel.DataAnnotations.Schema;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationStrategy.Model{[Table("Student")]publicclassStudent{publicintId{get;set;}publicstringName{get;set;}publicstringSex{get;set;}publicintAge{get;set;}publicstringEmail{get;set;}publicstringAddress{get;set;}}}

Program类定义如下:

usingInitializationStrategy.EF;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationStrategy{classProgram{staticvoidMain(string[]args){using(varcontext=newSampleDbEntities()){foreach(varitemincontext.Students){}}Console.WriteLine("创建成功");Console.ReadKey();}}}

运行程序后,数据库表结构如下:

Entity Framework如何使用Code First模式管理数据库

注意:如果处于生产环境,那么我们肯定不想丢失已经存在的数据。这时我们就需要关闭该初始化器,只需要将null传给Database.SetInitlalizer()方法,如下所示:

publicSampleDbEntities():base("name=AppConnection"){Database.SetInitializer<SampleDbEntities>(null);}

2、填充种子数据

到目前为止,无论我们选择哪种策略初始化数据库,生成的数据库都是一个空的数据库。但是许多情况下我们总想在数据库创建之后、首次使用之前就插入一些数据。此外,开发阶段可能想以admin的资格为其填充一些数据,或者为了测试应用在特定的场景中表现如何,想要伪造一些数据。

当我们使用DropCreateDatabaseAlways和DropCreateDatabaseIfModelChanges初始化策略时,插入种子数据非常重要,因为每次运行应用时,数据库都要重新创建,每次数据库创建之后在手动插入数据非常乏味。接下来我们看一下当数据库创建之后如何使用EF来插入种子数据。

为了向数据库插入一些初始化数据,我们需要创建满足下列条件的数据库初始化器类:

1、从已存在的数据库初始化器类中派生数据。
2、在数据库创建期间种子化。

下面演示如何初始化种子数据

1、定义领域实体类
usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel.DataAnnotations.Schema;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationSeed.Model{[Table("Employee")]publicclassEmployee{publicintEmployeeId{get;set;}publicstringFirstName{get;set;}publicstringLastName{get;set;}}}
2、创建数据库上下文

使用EF的Code First方式对上面的模型创建数据库上下文:

publicclassSampleDbEntities:DbContext{publicvirtualDbSet<Employee>Employees{get;set;}}

3、创建数据库初始化器类

假设我们使用的是DropCreateDatabaseAlways数据库初始化策略,那么初始化器类就要从该泛型类继承,并传入数据库上下文作为类型参数。接下来,要种子化数据库就要重写DropCreateDatabaseAlways类的Seed()方法,而Seed()方法拿到了数据库上下文,因此我们可以使用它来将数据插入数据库:

usingInitializationSeed.Model;usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Entity;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationSeed.EF{///<summary>///数据库初始化器类///</summary>publicclassSeedingDataInitializer:DropCreateDatabaseAlways<SampleDbEntities>{///<summary>///重写DropCreateDatabaseAlways的Seed方法///</summary>///<paramname="context"></param>protectedoverridevoidSeed(SampleDbEntitiescontext){for(inti=0;i<6;i++){varemployee=newEmployee{FirstName="测试"+(i+1),LastName="工程师"};context.Employees.Add(employee);}base.Seed(context);}}}

上面的代码通过for循环创建了6个Employee对象,并将它们添加给数据库上下文类的Employees集合属性。这里值得注意的是我们并没有调用DbContext.SaveChanges()方法,因为它会在基类中自动调用。

4、将数据库初始化器类用于数据库上下问类

usingInitializationSeed.Model;usingSystem;usingSystem.Collections.Generic;usingSystem.Data.Entity;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationSeed.EF{publicclassSampleDbEntities:DbContext{publicSampleDbEntities():base("name=AppConnection"){//类型传SeedingDataInitializerDatabase.SetInitializer<SampleDbEntities>(newSeedingDataInitializer());}//领域实体添加到数据上下文中publicvirtualDbSet<Employee>Employees{get;set;}}}

5、Main方法中访问数据库

usingInitializationSeed.EF;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceInitializationSeed{classProgram{staticvoidMain(string[]args){using(varcontext=newSampleDbEntities()){foreach(varitemincontext.Employees){Console.WriteLine("FirstName:"+item.FirstName+""+"LastName:"+item.LastName);}}Console.WriteLine("读取完成");Console.ReadKey();}}}

6、运行程序,查看结果

Entity Framework如何使用Code First模式管理数据库

查看数据库

Entity Framework如何使用Code First模式管理数据库

种子数据填充完成。

7、使用数据迁移的方式填充种子数据

使用数据迁移的方式会生成Configuration类,Configuration类定义如下:

namespaceDataMigration.Migrations{usingSystem;usingSystem.Data.Entity;usingSystem.Data.Entity.Migrations;usingSystem.Linq;internalsealedclassConfiguration:DbMigrationsConfiguration<DataMigration.SampleDbEntities>{publicConfiguration(){AutomaticMigrationsEnabled=false;}protectedoverridevoidSeed(DataMigration.SampleDbEntitiescontext){//Thismethodwillbecalledaftermigratingtothelatestversion.//YoucanusetheDbSet<T>.AddOrUpdate()helperextensionmethod//toavoidcreatingduplicateseeddata.}}}

重写Configuration类的Seed()方法也可以实现插入种子数据,重写Seed()方法:

namespaceDataMigration.Migrations{usingDataMigration.Model;usingSystem;usingSystem.Data.Entity;usingSystem.Data.Entity.Migrations;usingSystem.Linq;internalsealedclassConfiguration:DbMigrationsConfiguration<DataMigration.SampleDbEntities>{publicConfiguration(){AutomaticMigrationsEnabled=false;}protectedoverridevoidSeed(DataMigration.SampleDbEntitiescontext){//Thismethodwillbecalledaftermigratingtothelatestversion.//YoucanusetheDbSet<T>.AddOrUpdate()helperextensionmethod//toavoidcreatingduplicateseeddata.context.Employees.AddOrUpdate(newEmployee{FirstName="测试1",LastName="工程师"},newEmployee{FirstName="测试2",LastName="工程师"});}}}

使用数据迁移,然后查看数据库结果:

Entity Framework如何使用Code First模式管理数据库

发现使用数据迁移的方式也将种子数据插入到了数据库中。

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Entity Framework如何使用Code First模式管理数据库的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:vue中如何使用定义好的变量设置css样式下一篇:

8 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18