Entity Framework技术系列之2:三种开发模式实现数据访问
前言
Entity Framework支持Database First、Model First和Code Only三种开发模式,各模式的开发流程大相径庭,开发体验完全不一样。三种开发模式各有优缺点,对于程序员没有哪种模式最好,只有哪种模式更适合。接下来我将分别使用这三种开发模式实现同一数据库模型的数据持久化功能。希望通过实践能帮助你找到更适合你的开发模式。
Database First
Database First开发模式指以数据库设计为基础,并根据数据库自动生成实体数据模型,从而驱动整个开发流程。该模式的好处在于使用简单,容易入手。
为了降低学习难度,本文的数据库模型设计得尽量简单,如下图所示:
图1数据库模型图
对应的DDL语句如下:
1 --创建表 2 CREATE TABLE [User]( 3 [ID] [uniqueidentifier] NOT NULL, 4 [Name] [nvarchar](40) NOT NULL, 5 PRIMARY KEY CLUSTERED([ID] ASC) ON [PRIMARY]) 6 GO 7 8 CREATE TABLE [Role]( 9 [ID] [uniqueidentifier] NOT NULL, 10 [Name] [nvarchar](40) NOT NULL, 11 PRIMARY KEY CLUSTERED([ID] ASC) ON [PRIMARY]) 12 GO 13 14 CREATE TABLE [UserRole]( 15 [UserID] [uniqueidentifier] NOT NULL, 16 [RoleID] [uniqueidentifier] NOT NULL, 17 PRIMARY KEY CLUSTERED([UserID] ASC, [RoleID] ASC) ON [PRIMARY]) 18 GO 19 20 --创建外键 21 ALTER TABLE [UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_User] FOREIGN KEY([UserID]) 22 REFERENCES [User] ([ID]) 23 ON DELETE CASCADE 24 GO 25 26 ALTER TABLE [UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_Role] FOREIGN KEY([RoleID]) 27 REFERENCES [Role] ([ID]) 28 ON DELETE CASCADE 29 GO
创建名为“DatabaseFirst”的数据库,并执行以上的DDL语句,就可以建立本示例所需的数据库对象了。
在Visual Studio解决方案的DatabaseFirst项目中,添加一个名为DatabaseFirst.edmx的ADO.NET实体数据模型,如下图所示:
图2添加ADO.NET实体数据模型
点击“添加”按钮后,进入创建实体数据模型向导的选择模型内容界面,如下图所示:
图3选择从数据库生成模型
选择“从数据库生成”图标,并点击“下一步”按钮,进入选择数据连接界面,如下图所示:
图4设置数据连接
指定你的本地数据连接,选择“是,在连接字符串中包括敏感数据”选项,并为实体连接设置名称为“DatabaseFirst”,点击“下一步”按钮,进入选择数据库对象界面,如下图所示:
图5选择数据库对象
可供选择的数据库对象包括表、视图和存储过程。按上图所示设置后,点击“完成”按钮,Visual Studio将自动完成从Database到实体数据模型的生成工作。如下图所示:
图6由数据库生成的实体对象模型
至于生成内容的细节,在此就不作说明了,后续会用一整篇文章来深入剖析实体数据模型的方方面面。
至此,实体数据模型的建立算是完成了。在测试项目的应用程序配置文件中加入数据库连接配置,如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <configuration> 3 <connectionStrings> 4 <add name="DatabaseFirst" providerName="System.Data.EntityClient" 5 connectionString="provider=System.Data.SqlClient; 6 provider connection string=" 7 Data Source=localhost; 8 User Id=sa; 9 Password=11111111; 10 Initial Catalog=DatabaseFirst; 11 Integrated Security=False; 12 MultipleActiveResultSets=True;"; 13 metadata=res://*/DatabaseFirst.csdl| 14 res://*/DatabaseFirst.ssdl| 15 res://*/DatabaseFirst.msl"/> 16 </connectionStrings> 17 </configuration>
使用该实体数据模型的测试代码如下:
1 using Apollo.Blog.EF.Chapter2.DatabaseFirst; 2 … 3 4 using (var db = new DatabaseFirst.DatabaseFirst()) 5 { 6 var role = new Role(); 7 role.ID = Guid.NewGuid(); 8 role.Name = "Administrator"; 9 db.Roles.AddObject(role); 10 11 var user = new User(); 12 user.ID = Guid.NewGuid(); 13 user.Name = "Apollo"; 14 user.Roles.Add(role); 15 db.Users.AddObject(user); 16 17 db.SaveChanges(); 18 }
Model First
Model First开发模式是指从建立实体数据模型入手,并依据模型生成数据库,从而驱动整个开发流程。该模式也就是业界流行的面向领域的编程模式,它的优点在于,程序员可以用与设计建模相同的思维来进行代码编写,更符合面向对象的思想。Model First与Database First是互逆的,但最终都是输出数据库和实体数据模型。
在Visual Studio解决方案的ModelFirst项目中,添加一个名为ModelFirst.edmx的ADO.NET实体数据模型,如下图所示:
图7添加ADO.NET实体数据模型
点击“添加”按钮后,进入创建实体数据模型向导的选择模型内容界面,如下图所示:
图8选择空模型进行建模
选择“空模型”,点击“完成”按钮,,Visual Studio将新建一个空的实体数据模型。如下图所示:
图9生成的空模型
工具箱中提供了建模需要的实体、关联和继承元素。通过使用这些元素,建立如下的实体数据模型:
图10手动建模
用XML(文本)编辑器的方式打开ModelFirst.edmx文件,可以看到SSDL和MSL部分的映射代码是空的,而只产生了CSDL部分的代码;与此同时,查看ModelFirst.Designer.cs文件,发现实体类和上下文环境类已经创建了。我们只需将SSDL和MSL部分的代码产生就大功告成了。
首先,先使用SQL Server Management Studio工具创建一个名为ModelFirst的空数据库,如下图所示:
图11创建数据库
。然后,在Visual Studio中双击ModelFirst.edmx,回到模型关系图视图,在视图的空白处点击鼠标右键,打开右键菜单,如下图所示:
图12根据模型生成数据库
选择“根据模型生成数据库”菜单项,将进入“生成数据库”向导,如下图所示:
图13设置数据库连接
选择ModelFirst数据连接(如果是第一次使用钙连接,请使用 “新建连接”按钮新建一个指向ModelFirst数据库的连接),并按上图所示设置后,点击“下一步”按钮,进入“摘要和设置”界面,如下图所示:
图14自动生成的DDL内容
此时,Visual Studio已经自动生成了DDL语句,点击“完成”按钮,将ModelFirst.edmx.sql文件加入项目中。此时,再用XML(文本)编辑器的方式打开ModelFirst.edmx文件,可以看到SSDL和MSL部分的映射代码也已经生成了。对比ModelFirst和DatabaseFirst生成的.edmx文件和.Designer.cs后台文件,会发现两者内容其实是一样的。
数据库对象的生成有两种方式,一种是在SQL Server Management Studio中执行ModelFirst.edmx.sql;另一种是使用生成的上下文环境类创建:
1 using (var db = new ModelFirst.ModelFirstContainer()) 2 { 3 if (!db.DatabaseExists()) 4 db.CreateDatabase(); 5 }
至此,实体数据模型的建立算是完成了。在测试项目的应用程序配置文件中加入数据库连接配置,如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <configuration> 3 <connectionStrings> 4 <add name="ModelFirstContainer" providerName="System.Data.EntityClient" 5 connectionString="provider=System.Data.SqlClient; 6 provider connection string=" 7 Data Source=localhost; 8 User Id=sa; 9 Password=11111111; 10 Initial Catalog=ModelFirst; 11 Integrated Security=False; 12 MultipleActiveResultSets=True;"; 13 metadata=res://*/ModelFirst.csdl| 14 res://*/ModelFirst.ssdl| 15 res://*/ModelFirst.msl"/> 16 </connectionStrings> 17 </configuration>
使用该实体数据模型的测试代码如下:
1 using Apollo.Blog.EF.Chapter2.ModelFirst; 2 … 3 4 using (var db = new ModelFirst.ModelFirstContainer()) 5 { 6 var role = new Role(); 7 role.ID = Guid.NewGuid(); 8 role.Name = "Administrator"; 9 db.Roles.AddObject(role); 10 11 var user = new User(); 12 user.ID = Guid.NewGuid(); 13 user.Name = "Apollo"; 14 user.Roles.Add(role); 15 db.Users.AddObject(user); 16 17 db.SaveChanges(); 18 }
Code Only
Code Only开发模式也叫Code First开发模式,指的是程序员完全通过手动编码,就可以使用Entity Framewokr技术来实现数据访问。该模式的优点在于,支持POCO(Plain Old CLR Objects,简单传统CLR对象),代码整洁,程序员对代码的控制也更灵活自如。Code Only模式的代码结构如下图所示:
图15 Code Only开发模式的代码结构
Code Only开发模式需要Entity Framework Feature CTP支持,建议下载并安装最新的Entity Framework Feature CTP 5。安装后,Visual Studio解决方案的为CodeOnly项目添加该组件安装目录下的EntityFramework.dll库引用。
接下来在该项目中添加Role和User两个POCO类。其中,Role.cs主要代码如下:
1 public class Role 2 { 3 public Guid ID { get; set; } 4 5 public string Name { get; set; } 6 7 public IList<User> Users { get; set; } 8 }
User.cs主要代码如下:
1 public class User 2 { 3 public Guid ID { get; set; } 4 5 public string Name { get; set; } 6 7 public IList<Role> Roles { get; set; } 8 }
然后,创建一个对象上下文环境EntityContext.cs,主要代码如下:
1 using System.Data.Entity; 2 … 3 public class EntityContext : DbContext 4 { 5 public EntityContext() : base("CodeOnly") { } 6 7 public DbSet<Role> Roles { get; set; } 8 9 public DbSet<User> Users { get; set; } 10 }
OK,实体数据模型建成了。在测试项目的应用程序配置文件中加入数据库连接配置,如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <configuration> 3 <connectionStrings> 4 <add name="CodeOnly" connectionString="data source=YILIN;initial catalog=CodeOnly;persist security info=True;user id=sa;password=11111111" providerName="System.Data.SqlClient"/> 5 </connectionStrings> 6 </configuration>
使用该实体数据模型的测试代码如下:
1 using (var db = new EntityContext()) 2 { 3 db.Database.CreateIfNotExists(); 4 5 var role = new Role(); 6 role.ID = Guid.NewGuid(); 7 role.Name = "Administrator"; 8 db.Roles.Add(role); 9 10 var user = new User(); 11 user.ID = Guid.NewGuid(); 12 user.Name = "Apollo"; 13 user.Roles = new List<Role>() { role }; 14 db.Users.Add(user); 15 16 Assert.IsTrue(db.SaveChanges() > 0); 17 }
可以看到,得益于Entity Framework Feature CTP 5对Entity Framework的扩展,使得我们以Code Only模式编程时,几乎感觉不到Entity Framework的存在,也就是几乎不用做另外的事情去适应它,这是一件很美好的事情。并且,微软官方承诺了将把Entity Framework Feature CTP 5的内容纳入到.NET Framework的后续版本中,届时将不再需要另外下载并安装Entity Framework Feature CTP 5,Entity Framework本身就支持这些特性了。
总结
本文依次使用Entity Framework支持的Database First、Model First和Code Only三种开发模式实现数据的快速访问。Database First是Entity Framework最早支持,也是最容易上手的一种开发模式,建议初学者选择该模式入手;Model First模式也即面向领域的编程模式,该模式更能体现面向对象的思想;Code Only模式适合对Entity Framework技术较熟悉的程序员,它能让你的代码更整洁、更易维护。
接下来,我将对实体数据模型进行剖析,详细讲解Entity Framework如何实现对象-关系映射这一ORM的核心功能;在此基础上,给出一种DIY实体数据模型,实现对POCO和多数据库的支持。