原文地址:http://blog.csdn.net/hongsejiaozhu/article/details/44002179
我们将使用AdventureWorks数据库来进行今天的所有演示,因此开始之前请准备好相应的数据库。在EF中进行查询应该说是相当简单,只需要定义一个类继承于“DbContext”,然后定义对应的“DbSet”集合属性即可。例如下面的“AdventureWorksContext”类:
<span style="color: blue;">using </span>System.Data.Entity; <span style="color: blue;">using </span>System.Data.Entity.Infrastructure; <span style="color: blue;">using </span>EFPowerTools.Models.Mapping; <span style="color: blue;">namespace </span>EFPowerTools.Models { <span style="color: blue;">public partial class </span><span style="color: rgb(43, 145, 175);">AdventureWorksContext </span>: DbContext { <span style="color: blue;">static </span>AdventureWorksContext() { Database.SetInitializer<AdventureWorksContext>(<span style="color: blue;">null</span>); } <span style="color: blue;">public </span>AdventureWorksContext() : <span style="color: blue;">base</span>(<span style="color: rgb(163, 21, 21);">"Name=AdventureWorksContext"</span>) { } <span style="color: blue;">public </span>DbSet<Employee> Employees { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } <span style="color: blue;">public </span>DbSet<Person> People { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } } }
一个数据库上下文的生命周期随着该对象的创建而开始,随着对象的释放(或GC回收)而结束,因此建议在开发过程中使用“Using”编码方式,这样就可以免去手动释放对象的操作。如下面的代码:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.People.Where(p => p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens"</span>).OrderBy(p=>p.FirstName); <span style="color: blue;">foreach</span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
另外对于数据库连接的管理在EF中是透明的,我们一般不需要手动进行处理,当查询一个对象时打开连接当处理完查询的结果集之后会自动关闭连接。
在EF的Code First模式中有三种常用的数据查询方式(Model First和Database First中还有其他方式如:使用Entity SQL,但这不是我们今天的重点):Linq To Entity表达式查询、基于方法的查询、原生SQL查询。
查询表达式是C#3.0新增的功能,它是由一组类似于T-SQL或XQuery声明性语句组成,CLR并不能直接读取这种查询表达式而是在编译时转换为对应的方法调用。如下面的例子:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = <span style="color: blue;">from </span>p <span style="color: blue;">in </span>db.People <span style="color: blue;">where </span>p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens" </span><span style="color: blue;">orderby </span>p.FirstName <span style="color: blue;">select </span>p; <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
基于方法的查询事实上是一组对象的扩展方法,同Linq查询不同的是这些方法可以直接被CLR识别并运行。
例如上面的方法我们可以转换为如下代码,他们的效果是一样的,返回的都是“IQueryable”对象:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.People.Where(p => p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens"</span>).OrderBy(p => p.FirstName); <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
EF还支持原生SQL查询(注意与Entity SQL区别),例如:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.People.SqlQuery(<span style="color: rgb(163, 21, 21);">"SELECT * FROM Person.Person WHERE LastName='Stevens'"</span>); <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
不仅如此,EF还支持非实体类型的查询:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.Database.SqlQuery<<span style="color: blue;">string</span>>(<span style="color: rgb(163, 21, 21);">"SELECT FirstName FROM Person.Person WHERE LastName='Stevens'"</span>).ToList(); <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0}"</span>, p); } } } } }
当然也支持无返回值的SQL命令:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { db.Database.ExecuteSqlCommand(<span style="color: rgb(163, 21, 21);">"UPDATE Person.Person SET NameStyle=1 WHERE BusinessEntityID='1813'"</span>); } } } }
在EF中添加操作一般有两种方式:一是直接创建对象,然后调用“DbSet”的”Add()”方法进行添加;二是调用数据库上下文的”Entry()”方法并设置对应的状态。无论使用哪种方式最终一定要调用“SaveChange()”进行提交。如:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>stephen = <span style="color: blue;">new </span>Person { BusinessEntityID=20778, PersonType=<span style="color: rgb(163, 21, 21);">"EM"</span>, NameStyle=<span style="color: blue;">false</span>, Title=<span style="color: rgb(163, 21, 21);">"Architec"</span>, FirstName=<span style="color: rgb(163, 21, 21);">"Stephen"</span>, LastName=<span style="color: rgb(163, 21, 21);">"Chow"</span>, EmailPromotion=1, rowguid = <span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; db.People.Add(stephen); <span style="color: blue;">var </span>jeffrey = <span style="color: blue;">new </span>Person { BusinessEntityID = 20779, PersonType = <span style="color: rgb(163, 21, 21);">"EM"</span>, NameStyle = <span style="color: blue;">false</span>, Title = <span style="color: rgb(163, 21, 21);">"Engineer"</span>, FirstName = <span style="color: rgb(163, 21, 21);">"Jeffrey"</span>, LastName = <span style="color: rgb(163, 21, 21);">"Lee"</span>, EmailPromotion = 0, rowguid=<span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate=<span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; db.Entry(jeffrey).State = EntityState.Added; db.SaveChanges(); } } } }
效果如图:
此外,在含有导航属性时,将一个对象赋值给另一个对象的导航属性也能达到添加的效果(当导航属性为”DbSet“集合时通过调用导航属性的“Add()“方法也同样可以达到添加效果),例如在”Person.Person”中我们上面添加了两条记录,但对于“Person”类的导航属性“EmailAddress”和“Password”在对应的“EmailAddress”表和“Password”表中并没有添加对应的记录,此时我们就可以通过下面的方式来增加:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>password = <span style="color: blue;">new </span>Password { BusinessEntityID=20778, PasswordHash = <span style="color: rgb(163, 21, 21);">"ZEgQH9qZIPiLgyBHYw/dD1FJQNpdQyIAa+BFfKX5/jg="</span>, PasswordSalt = <span style="color: rgb(163, 21, 21);">"7iy/umc="</span>, rowguid=<span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate=<span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; <span style="color: blue;">var </span>email = <span style="color: blue;">new </span>EmailAddress { BusinessEntityID = 20778, EmailAddress1 = <span style="color: rgb(163, 21, 21);">"[email protected]"</span>, rowguid = <span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; <span style="color: blue;">var </span>person = db.People.Find(20778); person.Password = password; person.EmailAddresses.Add(email); db.SaveChanges(); } } } }
此时查看将可以看到“EmailAddress”表中确实增加了一条记录(“Password”表同样也是如此):
在这里我们需要强调一点那就是状态跟踪,对于上面的操作如果我们调用“Attach()”方法对实体进行跟踪或者设置实体的状态那么数据将不会保存到数据库:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>stephen = <span style="color: blue;">new </span>Person { BusinessEntityID = 20778, PersonType = <span style="color: rgb(163, 21, 21);">"EM"</span>, NameStyle = <span style="color: blue;">false</span>, Title = <span style="color: rgb(163, 21, 21);">"Architec"</span>, FirstName = <span style="color: rgb(163, 21, 21);">"Stephen"</span>, LastName = <span style="color: rgb(163, 21, 21);">"Chow"</span>, EmailPromotion = 1, rowguid = <span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; db.People.Add(stephen); db.People.Attach(stephen); <span style="color: green;">//db.Entry(stephen).State = EntityState.Unchanged;//同上面db.People.Attach(stephen);作用一样 </span>db.SaveChanges(); } } } }
使用”Attach()”方法进行实体跟踪时会设置实体的状态为“Unchanged”此时实体处于未修改状态,当执行“SaveChange()”方法时EF不会执行修改操作。相反如果此时设置实体状态为“Modified”则EF执行更新操作。那么既然EF的数据修改操作(增加、更新、删除)是根据实体状态而进行的,那么为什么之前我们的增加操作能正常进行而不用手动修改其状态呢?原因是EF会自动发现状态改变,在调用下面的方法时状态发现是自动的:
· DbSet.Find · DbSet.Local · DbSet.Remove · DbSet.Add · DbSet.Attach · DbContext.SaveChanges · DbContext.GetValidationErrors · DbContext.Entry · DbChangeTracker.Entries |
当然,并不是所有的时候我们都需要EF自动发现状态改变,设置 “DbContext.Configuration.AutoDetectChangesEnabled”属性为“false”可以禁用自动发现功能。
注意:在EF对数据操作时有时会抛出: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 此时可以使用try{} catch(DbEntityValidationException ex){} 对异常进行捕获,将鼠标放到ex上并逐级查看ex的信息进行解决。 |
下面看一下EF的删除操作:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19977).FirstOrDefault(); db.EmailAddresses.Remove(mail); db.SaveChanges(); } } } }
当然有了上面状态跟踪的讨论相信大家也可以想到如下删除方法:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19976).FirstOrDefault(); db.Entry(mail).State = EntityState.Deleted; db.SaveChanges(); } } } }
修改数据很简单,直接修改对应的属性即可:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>person = db.People.Where(p => p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens"</span>).OrderBy(p=>p.BusinessEntityID).FirstOrDefault(); person.NameStyle = <span style="color: blue;">false</span>; person.EmailAddresses.First().EmailAddress1 = <span style="color: rgb(163, 21, 21);">"[email protected]"</span>; db.SaveChanges(); } } } }
需要说明的是,EF在执行修改操作前会检查哪些属性发生了变化,并且只会修改发生变化的字段。
今天的内容就先到这里了,从前面的EF5.0概览到现在的数据操作,关于EF5.0基础的入门内容已经说完了,更多内容敬请关注后面的文章。
我们将使用AdventureWorks数据库来进行今天的所有演示,因此开始之前请准备好相应的数据库。在EF中进行查询应该说是相当简单,只需要定义一个类继承于“DbContext”,然后定义对应的“DbSet”集合属性即可。例如下面的“AdventureWorksContext”类:
<span style="color: blue;">using </span>System.Data.Entity; <span style="color: blue;">using </span>System.Data.Entity.Infrastructure; <span style="color: blue;">using </span>EFPowerTools.Models.Mapping; <span style="color: blue;">namespace </span>EFPowerTools.Models { <span style="color: blue;">public partial class </span><span style="color: rgb(43, 145, 175);">AdventureWorksContext </span>: DbContext { <span style="color: blue;">static </span>AdventureWorksContext() { Database.SetInitializer<AdventureWorksContext>(<span style="color: blue;">null</span>); } <span style="color: blue;">public </span>AdventureWorksContext() : <span style="color: blue;">base</span>(<span style="color: rgb(163, 21, 21);">"Name=AdventureWorksContext"</span>) { } <span style="color: blue;">public </span>DbSet<Employee> Employees { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } <span style="color: blue;">public </span>DbSet<Person> People { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } } }
一个数据库上下文的生命周期随着该对象的创建而开始,随着对象的释放(或GC回收)而结束,因此建议在开发过程中使用“Using”编码方式,这样就可以免去手动释放对象的操作。如下面的代码:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.People.Where(p => p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens"</span>).OrderBy(p=>p.FirstName); <span style="color: blue;">foreach</span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
另外对于数据库连接的管理在EF中是透明的,我们一般不需要手动进行处理,当查询一个对象时打开连接当处理完查询的结果集之后会自动关闭连接。
在EF的Code First模式中有三种常用的数据查询方式(Model First和Database First中还有其他方式如:使用Entity SQL,但这不是我们今天的重点):Linq To Entity表达式查询、基于方法的查询、原生SQL查询。
查询表达式是C#3.0新增的功能,它是由一组类似于T-SQL或XQuery声明性语句组成,CLR并不能直接读取这种查询表达式而是在编译时转换为对应的方法调用。如下面的例子:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = <span style="color: blue;">from </span>p <span style="color: blue;">in </span>db.People <span style="color: blue;">where </span>p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens" </span><span style="color: blue;">orderby </span>p.FirstName <span style="color: blue;">select </span>p; <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
基于方法的查询事实上是一组对象的扩展方法,同Linq查询不同的是这些方法可以直接被CLR识别并运行。
例如上面的方法我们可以转换为如下代码,他们的效果是一样的,返回的都是“IQueryable”对象:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.People.Where(p => p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens"</span>).OrderBy(p => p.FirstName); <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
EF还支持原生SQL查询(注意与Entity SQL区别),例如:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.People.SqlQuery(<span style="color: rgb(163, 21, 21);">"SELECT * FROM Person.Person WHERE LastName='Stevens'"</span>); <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0},LastName:{1}"</span>, p.FirstName, p.LastName); } } } } }
不仅如此,EF还支持非实体类型的查询:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>persons = db.Database.SqlQuery<<span style="color: blue;">string</span>>(<span style="color: rgb(163, 21, 21);">"SELECT FirstName FROM Person.Person WHERE LastName='Stevens'"</span>).ToList(); <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>persons) { <span style="color: rgb(43, 145, 175);">Console</span>.WriteLine(<span style="color: rgb(163, 21, 21);">"FirstName:{0}"</span>, p); } } } } }
当然也支持无返回值的SQL命令:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { db.Database.ExecuteSqlCommand(<span style="color: rgb(163, 21, 21);">"UPDATE Person.Person SET NameStyle=1 WHERE BusinessEntityID='1813'"</span>); } } } }
在EF中添加操作一般有两种方式:一是直接创建对象,然后调用“DbSet”的”Add()”方法进行添加;二是调用数据库上下文的”Entry()”方法并设置对应的状态。无论使用哪种方式最终一定要调用“SaveChange()”进行提交。如:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>stephen = <span style="color: blue;">new </span>Person { BusinessEntityID=20778, PersonType=<span style="color: rgb(163, 21, 21);">"EM"</span>, NameStyle=<span style="color: blue;">false</span>, Title=<span style="color: rgb(163, 21, 21);">"Architec"</span>, FirstName=<span style="color: rgb(163, 21, 21);">"Stephen"</span>, LastName=<span style="color: rgb(163, 21, 21);">"Chow"</span>, EmailPromotion=1, rowguid = <span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; db.People.Add(stephen); <span style="color: blue;">var </span>jeffrey = <span style="color: blue;">new </span>Person { BusinessEntityID = 20779, PersonType = <span style="color: rgb(163, 21, 21);">"EM"</span>, NameStyle = <span style="color: blue;">false</span>, Title = <span style="color: rgb(163, 21, 21);">"Engineer"</span>, FirstName = <span style="color: rgb(163, 21, 21);">"Jeffrey"</span>, LastName = <span style="color: rgb(163, 21, 21);">"Lee"</span>, EmailPromotion = 0, rowguid=<span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate=<span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; db.Entry(jeffrey).State = EntityState.Added; db.SaveChanges(); } } } }
效果如图:
此外,在含有导航属性时,将一个对象赋值给另一个对象的导航属性也能达到添加的效果(当导航属性为”DbSet“集合时通过调用导航属性的“Add()“方法也同样可以达到添加效果),例如在”Person.Person”中我们上面添加了两条记录,但对于“Person”类的导航属性“EmailAddress”和“Password”在对应的“EmailAddress”表和“Password”表中并没有添加对应的记录,此时我们就可以通过下面的方式来增加:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>password = <span style="color: blue;">new </span>Password { BusinessEntityID=20778, PasswordHash = <span style="color: rgb(163, 21, 21);">"ZEgQH9qZIPiLgyBHYw/dD1FJQNpdQyIAa+BFfKX5/jg="</span>, PasswordSalt = <span style="color: rgb(163, 21, 21);">"7iy/umc="</span>, rowguid=<span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate=<span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; <span style="color: blue;">var </span>email = <span style="color: blue;">new </span>EmailAddress { BusinessEntityID = 20778, EmailAddress1 = <span style="color: rgb(163, 21, 21);">"[email protected]"</span>, rowguid = <span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; <span style="color: blue;">var </span>person = db.People.Find(20778); person.Password = password; person.EmailAddresses.Add(email); db.SaveChanges(); } } } }
此时查看将可以看到“EmailAddress”表中确实增加了一条记录(“Password”表同样也是如此):
在这里我们需要强调一点那就是状态跟踪,对于上面的操作如果我们调用“Attach()”方法对实体进行跟踪或者设置实体的状态那么数据将不会保存到数据库:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>stephen = <span style="color: blue;">new </span>Person { BusinessEntityID = 20778, PersonType = <span style="color: rgb(163, 21, 21);">"EM"</span>, NameStyle = <span style="color: blue;">false</span>, Title = <span style="color: rgb(163, 21, 21);">"Architec"</span>, FirstName = <span style="color: rgb(163, 21, 21);">"Stephen"</span>, LastName = <span style="color: rgb(163, 21, 21);">"Chow"</span>, EmailPromotion = 1, rowguid = <span style="color: rgb(43, 145, 175);">Guid</span>.NewGuid(), ModifiedDate = <span style="color: rgb(43, 145, 175);">DateTime</span>.Now }; db.People.Add(stephen); db.People.Attach(stephen); <span style="color: green;">//db.Entry(stephen).State = EntityState.Unchanged;//同上面db.People.Attach(stephen);作用一样 </span>db.SaveChanges(); } } } }
使用”Attach()”方法进行实体跟踪时会设置实体的状态为“Unchanged”此时实体处于未修改状态,当执行“SaveChange()”方法时EF不会执行修改操作。相反如果此时设置实体状态为“Modified”则EF执行更新操作。那么既然EF的数据修改操作(增加、更新、删除)是根据实体状态而进行的,那么为什么之前我们的增加操作能正常进行而不用手动修改其状态呢?原因是EF会自动发现状态改变,在调用下面的方法时状态发现是自动的:
· DbSet.Find · DbSet.Local · DbSet.Remove · DbSet.Add · DbSet.Attach · DbContext.SaveChanges · DbContext.GetValidationErrors · DbContext.Entry · DbChangeTracker.Entries |
当然,并不是所有的时候我们都需要EF自动发现状态改变,设置 “DbContext.Configuration.AutoDetectChangesEnabled”属性为“false”可以禁用自动发现功能。
注意:在EF对数据操作时有时会抛出: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 此时可以使用try{} catch(DbEntityValidationException ex){} 对异常进行捕获,将鼠标放到ex上并逐级查看ex的信息进行解决。 |
下面看一下EF的删除操作:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19977).FirstOrDefault(); db.EmailAddresses.Remove(mail); db.SaveChanges(); } } } }
当然有了上面状态跟踪的讨论相信大家也可以想到如下删除方法:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19976).FirstOrDefault(); db.Entry(mail).State = EntityState.Deleted; db.SaveChanges(); } } } }
修改数据很简单,直接修改对应的属性即可:
<span style="color: blue;">using </span>System; <span style="color: blue;">using </span>System.Collections.Generic; <span style="color: blue;">using </span>System.Data; <span style="color: blue;">using </span>System.Data.Entity.Validation; <span style="color: blue;">using </span>System.Linq; <span style="color: blue;">using </span>System.Text; <span style="color: blue;">using </span>System.Threading.Tasks; <span style="color: blue;">using </span>EFPowerTools.Models; <span style="color: blue;">using </span>System.Data.Objects; <span style="color: blue;">namespace </span>EFPowerTools { <span style="color: blue;">class </span><span style="color: rgb(43, 145, 175);">Program </span>{ <span style="color: blue;">static void </span>Main(<span style="color: blue;">string</span>[] args) { <span style="color: blue;">using </span>(<span style="color: blue;">var </span>db = <span style="color: blue;">new </span>AdventureWorksContext()) { <span style="color: blue;">var </span>person = db.People.Where(p => p.LastName == <span style="color: rgb(163, 21, 21);">"Stevens"</span>).OrderBy(p=>p.BusinessEntityID).FirstOrDefault(); person.NameStyle = <span style="color: blue;">false</span>; person.EmailAddresses.First().EmailAddress1 = <span style="color: rgb(163, 21, 21);">"[email protected]"</span>; db.SaveChanges(); } } } }
需要说明的是,EF在执行修改操作前会检查哪些属性发生了变化,并且只会修改发生变化的字段。
今天的内容就先到这里了,从前面的EF5.0概览到现在的数据操作,关于EF5.0基础的入门内容已经说完了,更多内容敬请关注后面的文章。