Entity Framework将概念模型中定义的实体和关系映射到数据源,利用实体框架可以将数据源返回的数据具体化为对象;跟踪对象所做的更改;并发处理;将对象更改传播到数据源等。今天我们就一起讨论如何利用Entity Framework进行查询、插入、更新和删除数据。

查询

我们将使用AdventureWorks数据库来进行今天的所有演示,因此开始之前请准备好相应的数据库。在EF中进行查询应该说是相当简单,只需要定义一个类继承于“DbContext”,然后定义对应的“DbSet”集合属性即可。例如下面的“AdventureWorksContext”类:

using System.Data.Entity; using System.Data.Entity.Infrastructure; using EFPowerTools.Models.Mapping; namespace EFPowerTools.Models { public partial class AdventureWorksContext : DbContext { static AdventureWorksContext() { Database.SetInitializer<AdventureWorksContext>(null); } public AdventureWorksContext() : base("Name=AdventureWorksContext") { } public DbSet<Employee> Employees { get; set; } public DbSet<Person> People { get; set; } } }

一个数据库上下文的生命周期随着该对象的创建而开始,随着对象的释放(或GC回收)而结束,因此建议在开发过程中使用“Using”编码方式,这样就可以免去手动释放对象的操作。如下面的代码:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.Where(p => p.LastName == "Stevens").OrderBy(p=>p.FirstName); foreach(var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } } 

另外对于数据库连接的管理在EF中是透明的,我们一般不需要手动进行处理,当查询一个对象时打开连接当处理完查询的结果集之后会自动关闭连接。

在EF的Code First模式中有三种常用的数据查询方式(Model First和Database First中还有其他方式如:使用Entity SQL,但这不是我们今天的重点):Linq To Entity表达式查询、基于方法的查询、原生SQL查询。

Linq To Entity表达式查询

查询表达式是C#3.0新增的功能,它是由一组类似于T-SQL或XQuery声明性语句组成,CLR并不能直接读取这种查询表达式而是在编译时转换为对应的方法调用。如下面的例子:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = from p in db.People where p.LastName == "Stevens" orderby p.FirstName select p; foreach (var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } } 

基于方法的查询

基于方法的查询事实上是一组对象的扩展方法,同Linq查询不同的是这些方法可以直接被CLR识别并运行。

例如上面的方法我们可以转换为如下代码,他们的效果是一样的,返回的都是“IQueryable”对象:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.Where(p => p.LastName == "Stevens").OrderBy(p => p.FirstName); foreach (var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } } 

原生SQL查询

EF还支持原生SQL查询(注意与Entity SQL区别),例如:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.SqlQuery("SELECT * FROM Person.Person WHERE LastName='Stevens'"); foreach (var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } } 

不仅如此,EF还支持非实体类型的查询:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.Database.SqlQuery<string>("SELECT FirstName FROM Person.Person WHERE LastName='Stevens'").ToList(); foreach (var p in persons) { Console.WriteLine("FirstName:{0}", p); } } } } } 

当然也支持无返回值的SQL命令:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { db.Database.ExecuteSqlCommand("UPDATE Person.Person SET NameStyle=1 WHERE BusinessEntityID='1813'"); } } } } 

增加

在EF中添加操作一般有两种方式:一是直接创建对象,然后调用“DbSet”的”Add()”方法进行添加;二是调用数据库上下文的”Entry()”方法并设置对应的状态。无论使用哪种方式最终一定要调用“SaveChange()”进行提交。如:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var stephen = new Person { BusinessEntityID=20778, PersonType="EM", NameStyle=false, Title="Architec", FirstName="Stephen", LastName="Chow", EmailPromotion=1, rowguid = Guid.NewGuid(), ModifiedDate = DateTime.Now }; db.People.Add(stephen); var jeffrey = new Person { BusinessEntityID = 20779, PersonType = "EM", NameStyle = false, Title = "Engineer", FirstName = "Jeffrey", LastName = "Lee", EmailPromotion = 0, rowguid=Guid.NewGuid(), ModifiedDate=DateTime.Now }; db.Entry(jeffrey).State = EntityState.Added; db.SaveChanges(); } } } } 

效果如图:

此外,在含有导航属性时,将一个对象赋值给另一个对象的导航属性也能达到添加的效果(当导航属性为”DbSet“集合时通过调用导航属性的“Add()“方法也同样可以达到添加效果),例如在”Person.Person”中我们上面添加了两条记录,但对于“Person”类的导航属性“EmailAddress”和“Password”在对应的“EmailAddress”表和“Password”表中并没有添加对应的记录,此时我们就可以通过下面的方式来增加:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var password = new Password { BusinessEntityID=20778, PasswordHash = "ZEgQH9qZIPiLgyBHYw/dD1FJQNpdQyIAa+BFfKX5/jg=", PasswordSalt = "7iy/umc=", rowguid=Guid.NewGuid(), ModifiedDate=DateTime.Now }; var email = new EmailAddress { BusinessEntityID = 20778, EmailAddress1 = "StephenChow@outlook.com", rowguid = Guid.NewGuid(), ModifiedDate = DateTime.Now }; var person = db.People.Find(20778); person.Password = password; person.EmailAddresses.Add(email); db.SaveChanges(); } } } } 

此时查看将可以看到“EmailAddress”表中确实增加了一条记录(“Password”表同样也是如此):

状态跟踪

在这里我们需要强调一点那就是状态跟踪,对于上面的操作如果我们调用“Attach()”方法对实体进行跟踪或者设置实体的状态那么数据将不会保存到数据库:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var stephen = new Person { BusinessEntityID = 20778, PersonType = "EM", NameStyle = false, Title = "Architec", FirstName = "Stephen", LastName = "Chow", EmailPromotion = 1, rowguid = Guid.NewGuid(), ModifiedDate = DateTime.Now }; db.People.Add(stephen); db.People.Attach(stephen); //db.Entry(stephen).State = EntityState.Unchanged;//同上面db.People.Attach(stephen);作用一样 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的删除操作:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19977).FirstOrDefault(); db.EmailAddresses.Remove(mail); db.SaveChanges(); } } } } 

当然有了上面状态跟踪的讨论相信大家也可以想到如下删除方法:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var mail = db.EmailAddresses.Where(m => m.EmailAddressID == 19976).FirstOrDefault(); db.Entry(mail).State = EntityState.Deleted; db.SaveChanges(); } } } } 

修改

修改数据很简单,直接修改对应的属性即可:

using System; using System.Collections.Generic; using System.Data; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; using System.Data.Objects; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var person = db.People.Where(p => p.LastName == "Stevens").OrderBy(p=>p.BusinessEntityID).FirstOrDefault(); person.NameStyle = false; person.EmailAddresses.First().EmailAddress1 = "KenshinCui@outlook.com"; db.SaveChanges(); } } } } 

需要说明的是,EF在执行修改操作前会检查哪些属性发生了变化,并且只会修改发生变化的字段。

今天的内容就先到这里了,从前面的EF5.0概览到现在的数据操作,关于EF5.0基础的入门内容已经说完了,更多内容敬请关注后面的文章。

- (void)configDelegate {
__weak typeof(self) weakSelf = self;
[self.delegate setSelectRowAtIndexPathBlock:^(id cell, NSIndexPath *indexPath) {
TMPremiereBrand *premiereBrand = (TMPremiereBrand *)weakSelf.data[indexPath.row];
TMSpecialTopicController *specialTopicController = [[TMSpecialTopicController alloc] init];
specialTopicController.premiereBrandID = premiereBrand.ID;
[weakSelf.navigationController pushViewController:specialTopicController animated:YES];
}];
}
 

Entity Framework 5.0系列之数据操作的更多相关文章

  1. Entity Framework 5.0系列之Code First数据库迁移

    我们知道无论是"Database First"还是"Model First"当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Cod ...

  2. Entity Framework 5.0系列之EF概览

    概述 在开发面向数据的软件时我们常常为了解决业务问题实体.关系和逻辑构建模型而费尽心机,ORM的产生为我们提供了一种优雅的解决方案.ADO.NET Entity Framework是.NET开发中一种 ...

  3. Entity Framework 5.0系列之EF概览-三种编程方式

    概述 在开发面向数据的软件时我们常常为了解决业务问题实体.关系和逻辑构建模型而费尽心机,ORM的产生为我们提供了一种优雅的解决方案.ADO.NET Entity Framework是.NET开发中一种 ...

  4. Entity Framework 5.0系列之自动生成Code First代码

    在前面的文章中我们提到Entity Framework的"Code First"模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework P ...

  5. 【转】Entity Framework 5.0系列之自动生成Code First代码

    在前面的文章中我们提到Entity Framework的“Code First”模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework Power Tools ...

  6. (转)Entity Framework 5.0系列之自动生成Code First代码

    原文地址:http://www.cnblogs.com/kenshincui/archive/2013/08/29/3290527.html 在前面的文章中我们提到Entity Framework的“ ...

  7. Entity Framework 5.0系列之约定配置

    Code First之所以能够让开发人员以一种更加高效.灵活的方式进行数据操作有一个重要的原因在于它的约定配置.现在软件开发越来复杂,大家也都试图将软件设计的越来越灵活,很多内容我们都希望是可配置的, ...

  8. 【转】Entity Framework 5.0系列之约定配置

    Code First之所以能够让开发人员以一种更加高效.灵活的方式进行数据操作有一个重要的原因在于它的约定配置.现在软件开发越来复杂,大家也都试图将软件设计的越来越灵活,很多内容我们都希望是可配置的, ...

  9. Entity Framework 6.0 入门系列 第一篇

    Entity Framework 6.0 入门系列 第一篇 好几年前接触过一些ef感觉不是很好用,废弃.但是 Entity Framework 6.0是经过几个版本优化过的产物,性能和功能不断完善,开 ...

随机推荐

  1. GIL与线程互斥锁

    GIL 是解释器级别的锁,是限制只有一个原生线程运行,防止多个原生线程之间修改底层的共享数据.而线程互斥锁是防止多个线程同时修改python内存空间的共享数据.

  2. .Net 对App.config和Web.config的访问操作(增、删、读、改)

    一.首先引用Configuration 1)App.config如下: using System.Configuration;//若果还没有Configuration,右键引用文件夹添加引用,在.NE ...

  3. ActionBar

    Android actionBar 修改背景色 本来是想着自定义标题栏,发现老是出错.貌似4.0以上版本都不能自定义标题栏(我到现在都搞不清标题栏和actionBar的区别到底是什么!).原来需要自定 ...

  4. Everything搜索结果显示0 Object

    比较过windows本身的文档搜索功能,Everything的本地文档搜索能力简直令人咋舌,更逆天的是软件本身体积很小. 问题:打开everything时,文件列表消失,软件下方信息为0 object ...

  5. juery与表单中name="nodeName"引起的冲突

    引入jquery时,表单中如果有name="nodeName"的表单项,会有一些奇怪的冲突. 表单HTML代码如下: <form id="formAddEquipN ...

  6. doxygen的使用(一)配置并生成文档

    原创文章,欢迎阅读,禁止转载. doxygen是个好用的文档生成工具,他的强大功能有很多介绍,我就不说了.自带的chm帮助手册很全面,包括功能.注释规范.怎么配置.工具用法等.doxygen的用法共3 ...

  7. 【转载】Android数据存储之SQLite

    SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎.它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行. 在Android中创建的SQLite数据库存储在:/d ...

  8. Android应用:横竖屏切换总结

    眨眼间,已经到了2016你年春节前,离上一篇博客的时间已经有6个月多,回想起这半年的种种,不得不说,学习和工作实在是太忙了,或许这就是程序员的真实写照吧. 写博客之初,主要的目的还是为了把自己的学习痕 ...

  9. [UCSD白板题] Changing Money

    Problem Introduction In this problem,you will design an algorithm for changing money optimally. Prob ...

  10. 黑马程序员-c语言-类型强制转换

    强制转换的条件: 1.当所声明的类型不能满足所符值的变量时,需要转换声明的类型,以便能够存储变量. 例如:short存储的最大值为32767,但是所要符值大于32767时,short类型不符合,需要转 ...