转载Entity Framework 5.0(EF first)中的添加,删除,修改,查询,状态跟踪操作
转载原出处:http://www.cnblogs.com/kenshincui/p/3345586.html
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基础的入门内容已经说完了,更多内容敬请关注后面的文章。
转载Entity Framework 5.0(EF first)中的添加,删除,修改,查询,状态跟踪操作的更多相关文章
- 在Entity Framework 4.0中使用 Repository 和 Unit of Work 模式
[原文地址]Using Repository and Unit of Work patterns with Entity Framework 4.0 [原文发表日期] 16 June 09 04:08 ...
- 开发 ASP.NET vNext 续篇:云优化的概念、Entity Framework 7.0、简单吞吐量压力测试
继续上一篇<开发 ASP.NET vNext 初步总结(使用Visual Studio 2014 CTP1)>之后, 关于云优化和版本控制: 我本想做一下MAC和LINUX的self-ho ...
- Entity Framework 5.0系列之Code First数据库迁移
我们知道无论是"Database First"还是"Model First"当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Cod ...
- Entity Framework 5.0
今天 VS2012 .net Framework 4.5 Entity Framework 5.0 三者共同发布了. ( EF5 Released ) 在介绍新特性之前,先与大家回顾一下EF版 ...
- 云优化的概念、Entity Framework 7.0、简单吞吐量压力测试
云优化的概念.Entity Framework 7.0.简单吞吐量压力测试 继续上一篇<开发 ASP.NET vNext 初步总结(使用Visual Studio 2014 CTP1)>之 ...
- 浅析Entity Framework Core2.0的日志记录与动态查询条件
前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core2.0的日志记录与动态查询条件 去 ...
- Entity Framework Core(EF Core) 最简单的入门示例
目录 概述 基于 .NET Core 的 EF Core 入门 创建新项目 更改当前目录 安装 Entity Framework Core 创建模型 创建数据库 使用模型 基于 ASP.NET Cor ...
- Entity Framework 6.0 常见异常及解决办法
Ø 简介 本文主要记录 EF(Entity Framework) 在平时的开发中可能遇到的异常,以及应该如何去解决. 1. System.InvalidOperationException 1) ...
- Asp.Net MVC4开发二: Entity Framework在Asp.Net MVC4中的应用
ORM作为一种数据库訪问机制已广泛地应用于各种项目其中,在.Net开发中,应用比較广泛的ORM框架大致有以下几个: 官方支持的有:Linq to SQL.Entity Framework.三方的有:N ...
随机推荐
- Android:删除模拟器中没用的应用
进入模拟器,Setting->apps ->找到相应的app,选择uninstall 即可!
- C#基础精华02(静态类,值类型,引用类型,枚举,结构,ref与out)
静态类 静态类不能被其他类继承,静态成员亦不能被继承(访问的是同一个),备注1. 静态类只能继承自Object类.(静态类不能继承自其它类.) 继承(多态).静态本身就是相反的. 静态类不能实现任何接 ...
- 关于 hot code replace fail 问题 .
频频出现Hot code replace failed问题.网上查不到解决方法,想来想去,是否是jvm的问题?我的jre使用自己下载的jdk1.6.07,而MyEclipse的jvm自带的是1.5.0 ...
- NPOI的版本查看
从github上clone源代码 git clone https://github.com/tonyqus/npoi.git 下载的版本库中,有一个名为Release Notes.txt的文件,在这个 ...
- Access增删改查 (持续更新中)
关于Access数据库(2003)的增删改查,其实和Sql大体差不多,但是还有很多不一样的地方.下面列几个容易犯的错误: 1.Access数据库的位置: conn = new OleDbConnec ...
- vijos p1071新年趣事之打牌
描述 过年的时候,大人们最喜欢的活动,就是打牌了.xiaomengxian不会打牌,只好坐在一边看着. 这天,正当一群人打牌打得起劲的时候,突然有人喊道:“这副牌少了几张!”众人一数,果然是少了.于是 ...
- Android UI设计系统-android selector 开始自定义样式
Selector的结构描述: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:a ...
- C++学习笔记:Vector容器
vector v:初始化一个0大小的向量 vector v(10):初始化一个10个大小的向量 push_back:增加一个元素 pop:删除一个元素,不返回 front:返回第一个元素 back:返 ...
- 新手学习数据库(一)用Powerdesigner设计数据库
说明: 一.学会用开发语言进行数据库编程,其关键是在于学会sql语言,开发语言只不过给程序员提供了一个操作数据库的接口罢了. 二. 本人也是初学者,采用的数据库设计软件是powerdesigner.利 ...
- 在MFC[转载]在MFC状态栏显示时间 状态栏显示时间
原文:在MFC状态栏显示时间,谢小哈皮儿 c/c++ vc 在mfc状态栏显示时间,在VC的控件中有个Status bar可以在窗体状态栏中添加日期和时间.其实通过简单的代码,你就能创建一个有时钟显示 ...
