[翻译] - <Entitye Framework> - 快速入门: 用代码优先部件创建模型

纯属学习上的记录, 非专业翻译, 如有错误欢迎指正!

原文地址: http://msdn.microsoft.com/en-us/library/gg696189(v=vs.103).aspx

在这个快速入门教程中, 将演示如何使用 EF 和代码优先部件.

这个快速入门教程演示了如何完成以下任务:

创建名为"School"的类库项目:

通过代码优先部分定义 "School" 概念模型:

定义一个派生自 DbContext 的类:

配置数据库的初始化:

检索数据并使数据持久化:

通过重新默认的代码优先约定来指定数据库名称:

映射到一个现有的数据库:

先决条件:

这个快速入门教程适合那些熟悉 Visual Studio 开发和 .NET Framework, 但是还没用过 EF 的开发者. 为了能够完成这个快速入门教程, 下列软件必须安装:

Microsoft Visual Studio 2010 或者更新版本.

最新发布的 EF 版本. (可以通过 NuGet中的'Entity Framework' 包获得)

欲了解更多信息, 请参考 Entity Framework Releases and Versioning.

创建一个类库项目:

  1. 打开 Visual Studio 2010 或更新版本

  2. 打开 文件(File) 菜单, 选择 新建(New), 然后选择 项目(Project).

  3. 在左边的窗格中, 选择 Visual C#, 然后选择 类库(Class Library) 模板.

  4. 输入 SchoolModel 作为项目名称(Project Name), 并输入 CodeFirstSample 作为解决方案名称(Solution Name). 注: 要为项目名称和解决方法名称指定不同的名称, 要选上位于 新建项目 窗口右下角的 为解决方案创建目录(Create directory fro solution) 选项.

通过代码优先附件定义 SchoolModel:

使用代码优先部件时, 通常要先写一个 .NET Framework 类要定义概念(域)模型. 该类不用继承任何基类或实现任何接口. 在本节中, 你将用 C# 代码来定义模型.

  1. 删除 SchoolModel 项目中的默认源代码文件 (Class.cs).

  2. 通过 NuGet 包添加对 EntityFramework 程序集的引用. 在 解决方案资源管理器(Solution Explorer), 右击位于项目名称下面的 引用(References) 文件夹, 选择 Manage NuGet Packages... 在 Manage NuGet Packages 窗口中, 选择 EntityFramework 包然后点击 Install. (译注: 点击了左边窗格的 Online 选项后便可以在中间的窗格找到 EF 包)

  注: 如果使用的是预发行版本, 你必须通过 Package Manager Console 操作. 通过以下步骤可以打开该窗口: 在 Visual Studio 的菜单栏中, 选择 工具(Tools) -> Library Package Manager -> Package Manager Console. 在命令窗口中输入以下代码: Install-Package EntityFramework –IncludePreRelease. 

  3. 在接下来的模型中, 注释被用于覆盖一些默认约定. 首先你必须添加对 System.ComponentModel.DataAnnotations.ddl 的引用才可以使用注释. 在 解决方法资源管理器 中, 右击 引用 文件夹(译注: 选择 添加引用). 选择 .NET 选项卡, 选择 System.ComponentModel.DataAnnotations 组件, 然后点 确定(OK).

  4. 在 SchoolModel 中添加一个新的类文件, 文件名为 ShoolModel.

  5. 用以下主题中的代码替换默认生成的类定义. School Model Definition Using Code First Development. (译注: 代码文件中对 System 和 System.Collection.Generic 程序集的引用必须保留)

定义一个派生自 DbContext 的类来访问 SchoolModel 中的模型:

为了能够使用实体对象访问数据, 你需要创建一个 System.Data.Entity.DbContext 类型的环境对象. 我们建议你定义一个继承自 DbContext 的类, 同时为在模型中定义的每个实体类型发布一个 System.Data.Entity.DbSet 属性.

DbSet 属性代表一次返回特定类型的所有实体的查询. 然而, 仅仅访问一个属性并不会执行查询. 欲了解更多信息, 请参考 Querying Data.

  1. 在 SchoolModel 中添加一个新的类文件, 文件名为 SchoolModel.Context.

  2. 复制以下主题中对 Context 类的定义代码: School Context Definition.

定义一个类来处理数据库的初始化策略:

在这个步骤中, 你将定义一个类来处理数据库的初始化策略. 这个是一个继承自 DropCreateDatabaseAlways 并且实现了 Seed 方法的类. 在这个教程的后面部分 ("检索数据并使数据持久化") 你将会用到这个类的一个实例来设置数据库的初始化策略. 在使用这个策略的时候, 数据库将会被重建, 且数据库中的数据也会被重新填充, 就好像第一次使用该应用程序一样.

提示:

如果你的数据库扩展了, 可以考虑使用 EF 4.3 中的 Code First Migrations. 欲了解更多信息, 请参考:

Automatic Migrations Walkthrough

Code-Based Migrations Walkthrough

  1. 在 SchoolModel 中添加一个新的类文件, 文件名为 SchoolContextInitialzer.

  2. 用以下话题中的代码代替默认生成的类定义: School Database Creation and Initialization Strategy.

 

接下来, 我们将创建一个控制台应用程序来查询项目中的模型, 更新实体对象, 并将数据存到数据库中去.

创建控制台应用程序

  1. 添加一个名为 SchoolModelTest 的控制台应用程序到 CodeFirstSample 解决方案中去.

  2. 通过 NuGet 添加对 EntityFramwork 程序集的引用(参考上文);

  3. 添加对 SchoolModel 类库项目的引用. 在 解决方案资源管理器 中, 右击 引用 文件夹, 选择 添加引用, 在 项目 选项卡中选择 SchoolModel 项目.

  4. 将该项目设置为启动项目. 在 解决方案资源管理器 中, 右击该项目, 并选择 设为启动项目(Set as StartUp project).

检索数据并使数据持久化:

当你的应用程序运行时, 下列事情将会发生:

  • 指向被继承的上下文环境类型的数据库的初始化策略. 这仅在该上下文环境第一次被应用程序使用时发生.
  • EF 使用默认的约定在 localhost\SQLEXPRESS 实例或 LocalDB 数据库服务器上创建数据库, 并用继承了 DbContext 的上下文环境类的全名来命名数据库 (CodeFirstModel.SchoolEntites). 欲了解更多有关连接字符串约定的信息, 请参考 Code First Conventions. 当应用程序第二次运行时, 除非模型有改动, 否则现有的数据库将会被继续使用. 如果模型改变了而你没有设置初始化的话, 以下错误将会被抛出: "The model backing the 'ContextName' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data." (大意: 数据库被创建以后, 'ContextName' 上下文环境发生了改变. 手动删除或者更新数据库, 或者通过 IDatabaseInitialzer 实例调用 Database.SetInitializer. 例如: DropCreateDatabaseIfModelChanges 策略将自动删除并重建数据库, 若有设置, 还将自动填充种子数据.)
  • DbContext 检查是否存在一个继承了 DbContext 的上下文环境类型的模型, 同时给定的连接字符串被缓存进应用程序中. 如果存在, 则直接使用该模型. 若不存在, DbContext 会根据已定义的 DbSet 属性计算出什么类型应该被包含在模型中, 然后使用默认的代码优先约定和你通过注释或动态 API 指定的附加设置来创建模型.

1. 用以下代码取代默认生成的 Program 类定义:

Program
 1 using SchoolModel;
 2 using System.Data.Entity;
 3 class Program
 4 {
 5     static void Main(string[] args)
 6     {
 7         // Configure School database creation and initialization Strategy.
 8         // The initialization strategy is called the first time 
 9         // the context is used in the application domain. 
10         Database.SetInitializer<SchoolEntities>(new SchoolContextInitializer());
11 
12         using (var context = new SchoolEntities())
13         {
14             var department = (from d in context.Departments
15                               where d.Name == "English"
16                               select d).FirstOrDefault();
17 
18             Console.WriteLine("Online Courses:");
19             foreach (var c in department.Courses.OfType<OnlineCourse>())
20             {
21                 Console.WriteLine("  " + c.Title);
22                 foreach (var i in c.Instructors)
23                     Console.WriteLine("Instructor: {0}, {1}", i.FirstName, i.LastName);
24             }
25 
26             Console.WriteLine();
27             // Query for the Physics course using LINQ 
28             var physics = (from c in context.Courses
29                            where c.Title == "Physics"
30                            select c).FirstOrDefault();
31 
32             // Use the Query method together with the LINQ’s Count method
33             // to get the count of Instructor entities related to this course in the database
34             // without actually loading all the instructors.
35             var instructorCount = context.Entry(physics)
36                 .Collection(c => c.Instructors)
37                 .Query()
38                 .Count();
39 
40             if (instructorCount == 0)
41             {
42                 Console.WriteLine("Add a new instructor to the {0} course", physics.Title);
43                 var physicsInstructor =
44                     new Instructor { LastName = "White", FirstName = "Anthony", HireDate = DateTime.Parse("1995-03-11") };
45 
46                 // The following line will associate the Instructor with the course
47                 // and also add the new instructor to the context.
48                 physics.Instructors.Add(physicsInstructor);
49 
50                 // Save new entities.
51                 int recordsAffected = context.SaveChanges();
52 
53                 // Two records were added:
54                 // One to the Instructor table and one to the InstructorCourse table.
55                 Console.WriteLine(
56                     "Saved {0} entities to the database.",
57                     recordsAffected);
58             }
59             else
60                 Console.WriteLine("Physics course has an instructor.");
61         }
62     }
63 }

2. 编译并运行该应用程序.
当你运行该应用程序时, CodeFirstModel.SchoolEntitier 数据库将会被创建. 同时 SchoolContextInitializer 填充了种子数据, 故你才能在控制台窗口上看到. 在数据库中并没有教师与 Physice 课程关联, 故一个新的教师会被创建出来并添加到数据库中去.

使用 SQL Server Management Studio 或 Visual Studio 来查看新创建的数据库. 如果你用的是 Visual Studio 11 Beta, 按以下步骤: 在 Visual Studio 11 Beta 的菜单栏中, 选择 视图(View) -> SQL Server Object Explorer. 然后右击 SQL Server, 选择 Add SQL Server. 在 Sever Name 中输入 (local)\v11.0. 打开 Databases 选项就可以看到 School 数据库

: 确保在查看完以后已经关闭数据库.

如果你再次运行应用程序, 数据库将会被删除, 然后重建, 种子数据也会被重新填充.

通过覆盖默认的代码优先约定来指定数据库名称:

修改有关数据库名称的该代码优先约定的一种方式就是, 添加一个 App.config 或 Web.config 文件, 其中要包含一个与你的上下文环境类型名称一样的连接字符串. .Config 文件应被添加到包含可执行程序集的项目中.

  1. 如果项目中没有 app.config 或 web.config 文件就添加一个. 右击项目名称, 点击 添加(Add), 选择 新建项(New Item), 选择 应用程序配置文件(Application Configuration File) 模板.

如果你用的是 Visual Studio 11 Beta, .config 文件会自动添加到你的项目中. 向该文件添加下方所示的 connectionStrings 元素.

connectionStrings
1 <connectionStrings>
2   <add
3     name="SchoolEntities" providerName="System.Data.SqlClient"
4     connectionString="Server=(localdb)\v11.0;Database=School;
5     Trusted_Connection=true;Integrated Security=True;MultipleActiveResultSets=True"/>
6 </connectionStrings>

如果你使用的是 Visual Studio 2010, 在 .config 文件中添加下方所示的 connectionStrings 元素.

connectionStrings
1 <connectionStrings>
2   <add
3     name="SchoolEntities" providerName="System.Data.SqlClient"
4     connectionString="Server=.\SQLEXPRESS;Database=School;
5     Trusted_Connection=true;Integrated Security=True;MultipleActiveResultSets=True"/>
6 </connectionStrings>

  2. 编译并运行应用程序.

当你成功运行应用程序时, 名为 School 的数据库将会被创建.

注: 使用代码优先时, 连接字符串必须为合格的数据库连接字符串. 而使用模型优先或数据库优先时, 连接字符串必须为 EntityConnection 字符串.

注: 确保连接字符串中有 "multipleactiveresultsers=true" 设置. 当你用 foreach(C#) 或 For Each(Visual Basic)读入相关对象时, EF 将会试着创建一个新的 Data Reader. 如果你没有把 multipleactiveresultsers 设置为 true 的话, 这个操作将会失败. 欲了解更多信息, 请参考 MSDN 上的 Using Multiple Active Result Sets (MARS). 你也可以把查询的结果保存到一个 List 容器中, 它允许你能在关闭 Data Reader 的情况下遍历容器中的实体对象引用.

映射到一个现有的数据库:

想象你已经拥有一个数据库(例如: 上文中创建的那个). 将代码优先指向一个已存在的数据库常用的一种方法是, 添加一个 App.config 或 Web.config 文件, 其中要包含一个与你的上下文环境类型名称一样的连接字符串. 如果完成了以上几个小节的所有步骤 ("通过覆盖默认的代码优先约定来指定数据库名称"), 那么你已经有 .config 文件和连接字符串. 回到你在 "检索数据并使数据持久化" 小节中写的代码. 将初始化数据库的那一行代码注释掉:

// Database.SetInitializer<SchoolEntities>(new SchoolContextInitializer());

如果你现在运行应用程序, 现有的 School 数据库将会被直接使用. 而 instructorCount 变量将不再是 0. 因为你上次运行应用程序时填充了一个新教师.

posted @ 2012-04-15 09:56  Howll Chen  阅读(968)  评论(0编辑  收藏  举报