问题:
在项目中,添加一个模型。
解决方案:
假设应用域中仅有一个实体类型:Person,包含姓名和手机号。
1、右击项目,选择添加->新建项。
2、在打开的对话框中,依次展开已安装->Visual C#项->数据,选择ADO.NET实体数据模型,命名为:Recipe1。点击添加。
3、选择空EF设计器模型,点击完成。这个向导将产生一个带设计器的空的概念模型。
4、右击设计界面,选择新增->实体。将打开如下窗口:
5、将实体名词改为:Person,实体集自动更新为People,这个People也将作为数据库的表名,它也是DbContext实例引用Person时使用的实体集名称,你也可以修改成其他名称。键属性使用默认值:确保创建键属性复选框勾选,属性名称为Id,并且属性类型为Int32;关于键属性名称也可以修改为其他有意义的名称。
6.点击确定,一个新的Person实体将显示在设计界面。
7.右击Person实体,选择新增->标量属性,一个新的标量属性将被添加到Person实体的属性栏之下。重命名该标量属性为FirstName。按照同样的方法添加LastName,MiddleName和PhoneNumber 3个标量属性。
8.选中Id属性,在属性窗口中查看其属性(如果属性窗口未打开,可以通过右击选中的属性选中属性或视图->属性窗口,或者F4快捷键)。确保StoreGeneratedPattern属性被设置为Identity。这标志着Id属性的值将由存储层(store layer database)生成。最后生成的数据库脚本将标记Id列为自增(identity)列,并且存储模型(storage model)知道数据库将自动管理这个列的值。
完整的概念模型如下所示:
9.现在,模型已经生成,但在最终产生数据库脚本之前,我们还需要其他一些操作,虽然这些操作并不是必须的,但还是提倡根据自己项目需要修改模型的属性。在模型的属性窗口,将实体容器名改为:EF6RecipesContext,并将数据库架构名称改为:Chapter2;保存修改。实体容器名派生自DbContext,保存模型中所有的实体集。
10.右击设计界面,选择“根据模型生成数据库”,可以选择一个已存在的数据库连接,或使用一个新的数据库连接。这里我们使用一个新的数据库连接。
命名数据库名称为:EF6Recipes。确定,产生一个新的数据库连接。下一步。
11.选择EF版本,默认选6.x。下一步,将预览数据库脚本。
12.点击完成,将打开Recipe1.edmx.sql文件。在该文件内右击,选择Excute
13.连接到服务器,脚本被执行。EF6Recipes数据库和Person表被生成。
原理:
EF设计器是生成和更新概念模型、存储模型和映射层的有力工具。设计器提供双向建模支持:既可以在一个空的设计器中生成一个模型;也可以导入已有的数据库生成一个概念模型、存储模型和映射层。当前版本的设计器支持有限循环建模,也就是可以从模型重新生成数据库也可以从数据库更新模型。
模型有大量的属性用于存储模型和数据库生成。在上面的例子中,我们改变了模型的2个属性,第一个是重命名模型的实体容器名称为EF6RecipesContext,该容器类从DbContext派生,包含实体数据模型中的所有实例和一个OnModelCreating方法。在整本书中,我们都将使用EF6RecipesContext作为上下文。
另外,我们还改变了数据库架构名词为“Chapter2”,默认为“dbo”。它表示生成的存储模型和数据库脚本的架构名称。
现在,我们将演示模型基本的插入和获取操作。
1.打开Program.cs文件。因为模型同Program类在同一个名称空间,所有不用引用模型的名称空间。简单起见,直接在Main方法中编写代码。
2.在Main方法中插入如下代码:
using (var context = new EF6RecipesContex()) { var person = new Person { FirstName = "Robert", MiddleName = "Allen", LastName = "Doe", PhoneNumber = "867-5309" }; context.People.Add(person); person = new Person { FirstName = "John", MiddleName = "K.", LastName = "Smith", PhoneNumber = "824-3031" }; context.People.Add(person); person = new Person { FirstName = "Billy", MiddleName = "Abert", LastName = "Minor", PhoneNumber = "907-2212" }; context.People.Add(person); context.SaveChanges(); } using (var context = new EF6RecipesContext()) { foreach (var person in context.People) { Console.WriteLine("{0} {1} {2},Phone:{3}", person.FirstName, person.MiddleName, person.LastName, person.PhoneNumber); } Console.ReadLine(); }
3.执行项目,输出结果如下:
最佳实践:
使用using语句创建数据库上下文的实例。
一般情况下,我们获取一个对象的实例,并将其赋值给一个变量,当变量超出作用域和对象不再被引用时,垃圾回收器将在某一时刻进行处理,回收利用对象的内存空间。但由于垃圾回收是不确切的,它按照其自身的机制回收利用资源,我们仅能进行部分控制。
DbContext实例包含一些系统资源比如像数据库连接等,这些我们都希望在DbContext实例不在使用时进行释放,而不是等待直到垃圾回收器进行回收。这是就适合使用using语句,但需要对象实现了IDispose接口。
using语句有一些好的特性:1、当代码执行离开using(){}块时,对象的Dispose方法将被调用;对于DbContext实例,Dispose方法将关闭任何活动的数据库连接,适当的清除需要释放的任何其他资源。2、不论代码执行离开using(){}块的方式是怎样的(return语句或异常)Dispose方法都会被执行。
另外提示一点:虽然DbContext实例的SaveChanges()方法有异步版本,但是在using代码块中不建议用异步版本,除非能保证在跳出using块之前异步方法已经执行完成。因为当代码执行跳出using块时,如果异步方法没有执行完,其DbContext实例被销毁的话,异步方法会报错。