使用EF代码优先函数库操作现有数据库.docx
《使用EF代码优先函数库操作现有数据库.docx》由会员分享,可在线阅读,更多相关《使用EF代码优先函数库操作现有数据库.docx(12页珍藏版)》请在冰豆网上搜索。
使用EF代码优先函数库操作现有数据库
使用EF“代码优先”函数库操作现有数据库
原文发表地址]:
UsingEF“CodeFirst”withanExistingDatabase
[原文发表时间]:
2010/8/411:
09AM
上个月我博客里提到了EntityFramework4新的“代码优先”开发模式。
EF“代码优先”类库启用超棒的编码至上的开发工作流来访问数据。
它让你可以:
·不需要打开一个设计工具或定义XML映射文件就可以进行开发。
·定义模型对象时只需写一个简单的类,而不需要指定基类。
·使用“惯例高于配置”的方式实现数据库持久化,不需要显式配置任何信息。
在我的第一篇文章里我介绍了EF“代码优先”类库,并示范了使用EF4默认的映射惯例来创建一个新的数据库。
这些默认惯例在新的应用程序里工作的很好,而且还避免你显式配置任何东西从/往数据库中映射类型。
后来我又写了第二篇自定义数据库结构映射的文章,讨论了覆盖默认的持久化映射规则,和自定义数据库结构的方法。
今天的文章我将回答最近很多人问我的问题:
“如何对现有的数据库使用EF代码优先类库?
”
使用EF“代码优先”类库操作现有数据库
实际上,EF代码优先类库和现有的数据库工作的非常好,而且还是一个很好的编码至上的开发模式。
特别是,你可以用“简单CLR对象”(即POCO)定义好模型对象,用默认的映射惯例,或用自定义的映射规则,从/往数据库里映射它们。
下面分步示范了使用EF“代码优先”类库操作现有数据库的方法。
第一步:
创建一个新的ASP.NETWeb应用程序项目
让我们从创建一个新的ASP.NETWeb应用程序项目开始。
我前两篇EF“代码优先”文章用的是ASP.NETMVC—这篇文章我将用ASP.NETWeb窗体(来实现)。
请注意,不论你使用哪种类型的ASP.NET应用程序,背后的EF理念都是相同的。
我们使用VS2010(或者免费的VisualWebDeveloper2010体验版)的“文件->新建项目”菜单,并选择“ASP.NETWeb应用程序”项目模板来创建新的程序。
VS2010里新的“ASP.NETWeb应用程序”项目是一个很好的初学者模板,它的默认母板布局页面设计使用的是CSS(我在以前的文章里提到了新的初学者项目模版)。
当创建完毕以后,你可以看到它里面包含下面这些文件:
我们并不需要这些文件(实际上也可以使用“ASP.NET空Web应用程序”模版)—但如果用它们的话,可以让我们的程序看起来更漂亮一些。
第二步:
添加对EF代码优先库的引用
下一步将为我们的项目添加对EF代码优先类库的引用。
在解决方案资源管理器上右击“引用”节点,并选择“添加引用”。
你需要引用“Microsoft.Data.Entity.Ctp.dll”文件,你下载并安装EF代码优先类库后,它安装在“\ProgramFiles\MicrosoftADO.NETEntityFrameworkFeatureCTP4\Binaries\”文件夹里。
添加完引用后,项目引用窗口类似下图:
第三步:
Northwind数据库
如果你的SQLServer数据库已经安装了Northwind(或者其它的数据库),你可以跳过这一步。
如果你尚未安装,可以在这里下载它。
你既可以使用里面的.SQL文件来将它安装到SQL数据库里,也可以拷贝Northwind.mdf这个SQLExpress文件到你应用程序的\App_Data文件夹里:
第四步:
创建我们的模型层
现在我们来写模型类,并使用EF“代码优先”类库将它们映射到我们的Northwind数据库。
下面就是所有要写的代码—就这些:
下面是这些代码的详细工作原理:
POCO模型类
EF“代码优先”类库允许我们使用“简单CLR对象”(即POCO)来表现数据库里的实体。
也就是说我们的模型类不需要继承自一个基类,也不需要实现任何的接口或特性(attribute)。
这样可以使我们的模型类型保持整洁并且“持久化无关”。
前面我们定义了两个POCO类—“Product”(产品)和“Category”(种类)—用来表示Northwind数据库里的“Product”(产品)和“Category”(种类)表。
两个类的属性分别对应表的各个列。
“Product”(产品)或“Category”(种类)的实例分别对应表里的一行。
可空列
请注意“Product”(产品)类里有些属性被定义成可空属性(即Decimal?
—说明它是一个可空类型)。
数据表的可空列(Nullablecolumn)的类型如果是值类型的话,在模型类里应该用可空属性表示:
如果在模型类中,你不会访问可空列,你可以选择省略它。
比如说,Northwind的“Product”(产品)表里的“QuantityPerUnit”是一个可空的nvarchar类型,而“UnitsOnOrder”列是一个可空的smallint型。
我在定义上面的“Product”(产品)类时省略掉了这些属性。
因为它们在数据库里是可空的,所以我在执行读取、插入、更新和删除操作时不会有任何问题。
关联属性和延迟加载
EF“代码优先”类库使应用数据库里的主键/外键关系时变得更容易,它们通过模型类的属性表示,我们可以通过遍历模型类来使用这些关系。
前面我们在“Product”(产品)类里定义了一个“Category”(种类)属性,在“Category”(种类)类里定义了一个“Product”(产品)属性。
通过访问这些属性,可以让我们使用两个表之间的主键/外键关系,并获取相关模型实例的引用。
注意,这些属性依然是“POCO”对象,不需要使用任何EF定义的集合类型来定义它们。
标记为“virtual”的关联属性默认采用的是延迟加载技术。
也就是说,如果你抓取的是“Product”(产品)实体,除非显式访问,则不会从数据库中加载它的“Category”(种类)方面的信息(除非当你在使用LINQ查询抓取Product对象时,显式指定获取Category的数据)。
EF场景(Context)类
一旦创建好了“Product”(产品)和“Category”(种类)POCO类,我们用EF“代码优先”类库来创建一个”场景(context)”类来从/往数据库映射我们的POCO模型类:
上面的“Northwind”类是一个场景(Context)类,用来从/往数据库映射我们的POCO模型类。
它从EF“代码优先”类库里的DbContext这个基类继承下来,通过两个属性来陈列数据库中相应的表。
在这个示例中,我们用默认的“惯例高于配置”映射规则来从/往数据库映射类型。
如果我们要让模型类的对象模型跟数据库的结构有些差异,我们也可以覆写“OnModelCreating”函数来指定自定义的映射规则。
我前面的EF“代码优先”类库文章讲解了相关方法。
第五步:
配置数据库连接字符串
我们已经写好了定义模型层的所有代码,在使用它之前最后一步是设置连接到数据库的连接字符串。
在我的第一篇EF“代码优先”类库文章里,我介绍了EF“代码优先”类库提供的一个很酷的选项,就是它可以为你自动创建/重新创建数据库的结构。
这个选项对新建应用系统开发的情况特别有用—它允许你在项目早期只关注与模型层,而不需要在模型改动时,花时间更新你的数据库结构。
更重要的是,这个数据库自动创建功能只是一个选项—它不是必须的。
如果你的数据库连接字符串指向的是一个已有的数据库,那EF“代码优先”类库不会自动创建一个新的。
而且这个自动创建选项只在你显式指明的情况下EF才会这样做—因此你不必担心它会删除并重建你的数据库,除非你显式地告诉它应该这么做。
在这篇文章里,我们不会自动创建数据库。
而是通过在web.config文件里添加一个“Northwind”连接字符串指向我们已有的Northwind数据库:
connectionString="datasource=.\SQLEXPRESS;IntegratedSecurity=SSPI;AttachDBFilename=|DataDirectory|\northwind.mdf;UserInstance=true"
providerName="System.Data.SqlClient"/>
EF“代码优先”类库在查找连接字符串时,按照惯例,根据场景(Context)类名来寻找。
因为我们的场景(Context)类名字叫“Northwind”,所以默认寻找名为“Northwind”连接字符串。
上面我们配置Northwind连接字符串使用本地的SQLExpress数据库,你也可以指向一个远程的SQL服务器。
第六步:
使用我们的模型类
现在让我们使用Northwind模型类写一个非常简单的页面,从数据库中显示一些数据。
我们从向ASP.NET项目,右击web项目,然后选择“添加->新项”,然后选择“使用母板的Web窗体(WebFormusingMasterPage)”文件模板。
我们把这个页面命名为“Product.aspx”并且采用ASP.NETWeb项目默认的初学者模板自带的“Site.master”母板页。
我们将在Product.aspx页面添加一个GridView>控件。
并配置它只显示Products(产品)的名称和价格:
而在后台文件里,通过编写下列的LINQ查询从我们的模型类来获取数据库中所有有效的产品(Product),并将它们绑定到上面的GridView控件上:
现在当我们运行项目并浏览Products.aspx页面时,我们可以得到类似下图的产品列表:
现在我们已经有了一个简单的应用程序,它基于现有数据库调用EF“代码优先”类库。
下载示例代码
你可以从这里下载完整的示例代码,它假设你已经安装了EF“代码优先”类库CTP4版本和SQLExpress。
其它代码示例
下面的代码演示了使用Northwind模型的其它常见用法。
跨关系查询
下面的LINQ查询演示了基于产品种类(Category)的名称来获取产品(Product)对象序列。
注意下图我们的LINQ查询跨越产品(Product)对象和与其相关的种类(Category)对象的属性的编写方式。
实际的过滤过程是在数据库引擎里面做的—中间层只需要返回产品(Product)对象集合(也就更有效率):
使用Find方法获取单个产品(Product)对象
除了允许你编写上面的LINQ查询以外,EF“代码优先”类库还支持对DbSet集合调用“Find()”方法,这样你就可以用类似下面的代码根据ID获取单个实例了:
插入一个新的种类(Category)
下面的代码演示了往数据库中添加一个新的种类(Category)的方法:
留意我们创建种类(Category)对象,给它的属性赋值,然后将它加到语境(Context)的Categories集合的方式。
接着我们调用语境(Context)对象的SaveChanges()把改动保存到数据库中。
添加一个新的种类(Category)和产品(Product)(并关联它们)
下面的代码演示了创建一个新的种类(Category)和一个新的产品(Product),并关联产品(Product)属于新建的种类(Category),最后将它们都保存进数据库:
留意上面我们可以通过将新建种类(Category)的实例赋值给新建产品(Product)的“Category”(种类)属性,将新建产品(Product)引用到新建种类(Category)实例。
我们不需要显式地设置CategoryID外键属性—这个会在保存进数据库时自动完成。
EF使用一个叫做“工作单元”的模式—它会跟踪语境(Context)里的多重改动,当“SaveChanges()”被调用时,它会将这些改动以原子事务的方式一并保存(要么全部成功保存,要么全部失败)。
这是保证你的数据库不会被污染(即有些保存了,有些却没有)的简便方法。
在上面的代码中,种类(Category)和产品(Product)要么全保存了,要么全部没有(会扔出来有一个异常)。
更新一个产品(Product)并保存
下面的代码演示了获取和更新一个产品(Product),并保存回数据库的方式。
前面我示例了使用Find()函数根据ProductID获取单个产品(Product)的方法。
下面我们写一个根据ProductName获取特定产品(Product)的LINQ查询:
我们可以做多次更改(任何对象,新建的对象也是)。
当我们调用SaveChanges()时,会以一个事务的形式将它们保存到数据库中。
默认惯例vs自定义映射规则
之前我们创建产品(Product)和种类(Category)类时,我们使用的是EF“代码优先”类库默认的惯例从/往数据库中映射类型。
这让我们避免了自己指定映射规则,保持干净的代码。
当然肯定也有你不喜欢数据库结构的时候,而希望有自己不同形状的模型类。
参见我的自定义数据库结构映射文章来了解使用EF指定自定义映射规则的方法。
这些方法也同样适用于已有的数据库。
总结
我的确很喜欢EF“代码优先”类库的功能,并认为它提供了极佳的编码至上的数据处理方式。
它很好,很强大。
我喜欢它是因为它让代码保持干净,可维护并且很简洁。
希望这三篇文章能够让你一瞥它的功能—针对新的或已有的数据库(的功能)。
你可以从这里下载EF“代码优先”类库CTP4版本。
未尽事宜请参看ADO.NET团队的文章:
·EFCTP4发布公报
·EFCTP4工作效率上的提高
·EFCTP4代码优先类库攻略
·数据注解(DataAnnotation)和代码优先类库
·代码优先类库的默认公约
·ScottHanselman的CTP4攻略
希望这能对您有所帮助。