问题:

    在项目中,添加一个模型。

解决方案:

    假设应用域中仅有一个实体类型:Person,包含姓名和手机号。

    1、右击项目,选择添加->新建项

    2、在打开的对话框中,依次展开已安装->Visual C#项->数据,选择ADO.NET实体数据模型,命名为:Recipe1。点击添加。

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型

    3、选择空EF设计器模型,点击完成。这个向导将产生一个带设计器的空的概念模型。

    4、右击设计界面,选择新增->实体。将打开如下窗口:

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型_02

    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)知道数据库将自动管理这个列的值。

    完整的概念模型如下所示:

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型_03

    9.现在,模型已经生成,但在最终产生数据库脚本之前,我们还需要其他一些操作,虽然这些操作并不是必须的,但还是提倡根据自己项目需要修改模型的属性。在模型的属性窗口,将实体容器名改为:EF6RecipesContext,并将数据库架构名称改为:Chapter2;保存修改。实体容器名派生自DbContext,保存模型中所有的实体集。

    10.右击设计界面,选择“根据模型生成数据库”,可以选择一个已存在的数据库连接,或使用一个新的数据库连接。这里我们使用一个新的数据库连接。

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型_04

命名数据库名称为:EF6Recipes。确定,产生一个新的数据库连接。下一步。

    11.选择EF版本,默认选6.x。下一步,将预览数据库脚本。

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型_05

    12.点击完成,将打开Recipe1.edmx.sql文件。在该文件内右击,选择Excute

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型_06

    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.执行项目,输出结果如下:

EF6 秘籍 2th:实体数据建模基础 (四)生成一个简单模型_EF构造简单模型_07

最佳实践:

    使用using语句创建数据库上下文的实例。

     一般情况下,我们获取一个对象的实例,并将其赋值给一个变量,当变量超出作用域和对象不再被引用时,垃圾回收器将在某一时刻进行处理,回收利用对象的内存空间。但由于垃圾回收是不确切的,它按照其自身的机制回收利用资源,我们仅能进行部分控制。

    DbContext实例包含一些系统资源比如像数据库连接等,这些我们都希望在DbContext实例不在使用时进行释放,而不是等待直到垃圾回收器进行回收。这是就适合使用using语句,但需要对象实现了IDispose接口。

    using语句有一些好的特性:1、当代码执行离开using(){}块时,对象的Dispose方法将被调用;对于DbContext实例,Dispose方法将关闭任何活动的数据库连接,适当的清除需要释放的任何其他资源。2、不论代码执行离开using(){}块的方式是怎样的(return语句或异常)Dispose方法都会被执行。

    另外提示一点:虽然DbContext实例的SaveChanges()方法有异步版本,但是在using代码块中不建议用异步版本,除非能保证在跳出using块之前异步方法已经执行完成。因为当代码执行跳出using块时,如果异步方法没有执行完,其DbContext实例被销毁的话,异步方法会报错。