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. C、C++、Java、go的语法区别

    详细C++.Java比较:http://www.cnblogs.com/stephen-liu74/archive/2011/07/27/2118660.html 一.C.C++的区别 在很大程度上, ...

  2. [10]APUE:信号

    [a] 常用信号 SIGABRT 调用 abort 函数时产生此信号,进程异常终止 SIGALRM 调用 alarm 或 setitimer 函数超时之后产生 SIGCHLD 子进程终止或 stop ...

  3. UITextField使用详解

    转iOS中UITextField使用详解 (1) //初始化textfield并设置位置及大小   UITextField *text = [[UITextField alloc]initWithFr ...

  4. BZOJ 1564: [NOI2009]二叉查找树

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1564 Description Input Output 只有一个数字,即你所能得到的整棵树的访 ...

  5. css大小单位px em rem的转换和详解

    css大小单位px em rem的转换和详解 PX特点1. IE无法调整那些使用px作为单位的字体大小:2. 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位:3. Firefox能 ...

  6. java线程池初步理解

    多线程基础准备 进程:程序的执行过程,持有资源和线程 线程:是系统中最小的执行单元,同一个进程可以有多个线程,线程共享进程资源 线程交互(同步synchronized):包括互斥和协作,互斥通过对象锁 ...

  7. python中文编码

    前面章节中我们已经学会了如何用 Python 输出 "Hello, World!",英文没有问题,但是如果你输出中文字符"你好,世界"就有可能会碰到中文编码问题 ...

  8. XML解析工具类

    public class XmlUtil { /* * 利用dom4j解析xml文件内容,并返回map数据形式 * path是.xml文件所在的路径 */ public static Map<S ...

  9. java中枚举(enum)小例子。之前学过枚举但是一直没用,这里有个枚举类帮你我理解下(很肤浅)

    直接上枚举类,代码简单易懂. package com.jy.modules.cims.data.interact.tbj.loan.request; /** * * @author shengzhou ...

  10. <转>exe & dll自我更新

    exe & dll自我更新 分类: c/c++ 2008-10-16 22:07 756人阅读 评论(1) 收藏 举报 exedlldelayapi游戏 exe与dll的自我更新     在改 ...