EF4.1: Add/Attach and Entity States(EF中的实体状态转换说明)
实体的状态,连接以及 SaveChanges 方法
数据库上下文对象维护内存中的对象与数据库中数据行之间的同步。这些信息在调用 SaveChanges方法被调用的时候使用。例如,当使用 Add 方法传递一个新的实体对象时,实体的状态被设置为 Added,在调用 SaveChanges方法的时候,数据库上下文使用 SQL 命令 Insert来插入数据。
实体的状态可能为如下之一:
Added. 实体在数据库中不存在。SaveChanges 方法必须执行 Insert 命令
Unchanged. 在调用 SaveChanges 的时候不需要做任何事情,当从数据库读取数据的时候,实体处于此状态。
Modified. 某些或者全部的实体属性被修改过. SaveChanges方法需要执行 Update 命令。
Deleted. 实体标记为已删除,SaveChanges 方法必须执行 Delete 命令。
Detached. 实体的状态没有被数据库上下文管理。
在桌面应用中,实体的状态改变典型地自动完成。在这种类型的应用中,你读取一个实体,然后修改某些属性的值,这使得实体的状态被自动修改为 Modified。然后,在调用 SaveChanged 的时候,实体框架生成 Update 命令进行更新,只有你修改的实际属性被更新。
但是,在 Web 应用程序中,这个处理序列不是连续的。因为数据库上下文读取的实体对象实例在页面被呈现之后被丢弃了。当 HttpPost Edit 方法被调用的时候,导致一个新的请求和一个新的数据库上下文对象被生成,所以,你必须手工设置实体的状态为 Modified。然后调用 SaveChanges 方法,实体框架更新数据库中数据行的所有列,因为数据库上下文没有办法知道你修改了哪些属性。
如果你希望 Update 语句仅仅更新你实际上修改的字段。你可以通过某种途径保存原有的数据值 ( 例如通过隐藏域 ),以便在 HttpPost Edit 方法被调用的时候这些值存在。然后,可以使用原始的数据来创建一个 Student 实体,使用 Attach 方法调用连接含有原始值的实体对象,然后,使用新的值来更新实体对象,最后再调用 SaveChanges 方法,更多的详细内容,可以查看 EF 团队的博客: Add/Attach and Entity States和Local Data。
Introduction
Version 4.1 of the Entity Framework contains both the Code First approach and the new DbContext API. This API provides a more productive surface for working with the Entity Framework and can be used with the Code First, Database First, and Model First approaches. This is the fourth post of a twelve part series containing collections of patterns and code fragments showing how features of the new API can be used.
The posts in this series do not contain complete walkthroughs. If you haven’t used EF 4.1 before then you should read Part 1 of this series and also Code First Walkthrough or Model and Database First with DbContext before tackling this post.
Entity states and SaveChanges
An entity can be in one of five states as defined by the EntityState enumeration. These states are:
- Added: the entity is being tracked by the context but does not yet exist in the database
- Unchanged: the entity is being tracked by the context and exists in the database, and its property values have not changed from the values in the database
- Modified: the entity is being tracked by the context and exists in the database, and some or all of its property values have been modified
- Deleted: the entity is being tracked by the context and exists in the database, but has been marked for deletion from the database the next time SaveChanges is called
- Detached: the entity is not being tracked by the context
SaveChanges does different things for entities in different states:
- Unchanged entities are not touched by SaveChanges. Updates are not sent to the database for entities in the Unchanged state.
- Added entities are inserted into the database and then become Unchanged when SaveChanges returns.
- Modified entities are updated in the database and then become Unchanged when SaveChanges returns.
- Deleted entities are deleted from the database and are then detached from the context.
The following examples show ways in which the state of an entity or an entity graph can be changed.
Adding a new entity to the context
A new entity can be added to the context by calling the Add method on DbSet. This puts the entity into the Added state, meaning that it will be inserted into the database the next time that SaveChanges is called. For example:
using (var context = new UnicornsContext())
{
var unicorn = new Unicorn { Name = "Franky", PrincessId = 1};
context.Unicorns.Add(unicorn);
context.SaveChanges();
}
Another way to add a new entity to the context is to change its state to Added. For example:
using (var context = new UnicornsContext())
{
var unicorn = new Unicorn { Name = "Franky", PrincessId = 1};
context.Entry(unicorn).State = EntityState.Added;
context.SaveChanges();
}
Finally, you can add a new entity to the context by hooking it up to another entity that is already being tracked. This could be by adding the new entity to the collection navigation property of another entity or by setting a reference navigation property of another entity to point to the new entity. For example:
using (var context = new UnicornsContext())
{
// Add a new princess by setting a reference from a tracked unicorn
var unicorn = context.Unicorns.Find(1);
unicorn.Princess = new Princess { Name = "Belle" }; // Add a new unicorn by adding to the collection of a tracked princess
var princess = context.Princesses.Find(2);
princess.Unicorns.Add(new Unicorn { Name = "Franky" }); context.SaveChanges();
}
Note that for all of these examples if the entity being added has references to other entities that are not yet tracked then these new entities will also added to the context and will be inserted into the database the next time that SaveChanges is called.
Attaching an existing entity to the context
If you have an entity that you know already exists in the database but which is not currently being tracked by the context then you can tell the context to track the entity using the Attach method on DbSet. The entity will be in the Unchanged state in the context. For example:
var existingUnicorn = GetMyExistingUnicorn(); using (var context = new UnicornsContext())
{
context.Unicorns.Attach(existingUnicorn); // Do some more work... context.SaveChanges();
}
In the example above the GetMyExistingUnicorn returns a unicorn that is known to exist in the database. For example, this object might have come from the client in an n-tier application.
Note that no changes will be made to the database if SaveChanges is called without doing any other manipulation of the attached entity. This is because the entity is in the Unchanged state.
Another way to attach an existing entity to the context is to change its state to Unchanged. For example:
var existingUnicorn = GetMyExistingUnicorn(); using (var context = new UnicornsContext())
{
context.Entry(existingUnicorn).State = EntityState.Unchanged; // Do some more work... context.SaveChanges();
}
Note that for both of these examples if the entity being attached has references to other entities that are not yet tracked then these new entities will also attached to the context in the Unchanged state.
Attaching an existing but modified entity to the context
If you have an entity that you know already exists in the database but to which changes may have been made then you can tell the context to attach the entity and set its state to Modified. For example:
var existingUnicorn = GetMyExistingUnicorn(); using (var context = new UnicornsContext())
{
context.Entry(existingUnicorn).State = EntityState.Modified; context.SaveChanges();
}
When you change the state to Modified all the properties of the entity will be marked as modified and all the property values will be sent to the database when SaveChanges is called. More about working with property values is covered in Part 5 of this series.
Note that if the entity being attached has references to other entities that are not yet tracked, then these new entities will attached to the context in the Unchanged state—they will not automatically be made Modified. If you have multiple entities that need to be marked Modified you should set the state for each of these entities individually.
Changing the state of a tracked entity
You can change the state of an entity that is already being tracked by setting the State property on its entry. For example:
var existingUnicorn = GetMyExistingUnicorn(); using (var context = new UnicornsContext())
{
context.Unicorns.Attach(existingUnicorn); // Entity is in Unchanged state
context.Entry(existingUnicorn).State = EntityState.Modified; context.SaveChanges();
}
Note that calling Add or Attach for an entity that is already tracked can also be used to change the entity state. For example, calling Attach for an entity that is currently in the Added state will change its state to Unchanged.
Insert or update pattern
A common pattern for some applications is to either Add an entity as new (resulting in a database insert) or Attach an entity as existing and mark it as modified (resulting in a database update) depending on the value of the primary key. For example, when using database generated integer primary keys it is common to treat an entity with a zero key as new and an entity with a non-zero key as existing. This pattern can be achieved by setting the entity state based on a check of the primary key value. For example:
public void InsertOrUpdate(DbContext context, Unicorn unicorn)
{
context.Entry(unicorn).State = unicorn.Id == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
Note that when you change the state to Modified all the properties of the entity will be marked as modified and all the property values will be sent to the database when SaveChanges is called. More about working with property values is covered in Part 5 of this series.
Summary
In this part of the series we talked about entity states and showed how to add and attach entities and change the state of an existing entity.
As always we would love to hear any feedback you have by commenting on this blog post.
For support please use the Entity Framework Forum.
Arthur Vickers
Developer
ADO.NET Entity Framework
EF4.1: Add/Attach and Entity States(EF中的实体状态转换说明)的更多相关文章
- 6.翻译:EF基础系列---什么是EF中的实体?
原文地址:http://www.entityframeworktutorial.net/basics/what-is-entity-in-entityframework.aspx EF中的实体就是继承 ...
- 7.翻译:EF基础系列---EF中的实体类型
原文地址:http://www.entityframeworktutorial.net/Types-of-Entities.aspx 在Entity Framework中有两种实体类型:一种是POCO ...
- ADO.NET EF 中的实体修改方法
http://www.cnblogs.com/zfz15011/archive/2010/05/30/1747486.html 1.传统修改模式,看下列代码 using (NorthwindEntit ...
- EF中的实体类型【Types of Entity in Entity】(EF基础系列篇8)
We created EDM for existing database in the previous section. As you have learned in the previous se ...
- Entity Framework入门教程(4)---EF中的实体关系
这一节将总结EF是怎么管理实体之间的关系.EF与数据库一样支持三种关系类型:①一对一 ,②一对多,③多对多. 下边是一个SchoolDB数据库的实体数据模型,图中包含所有的实体和各个实体间的关系.通过 ...
- MySql.Data.Entity 在EF中解析uint的枚举时有BUG
当枚举继承uint类型时无法获取值.
- EF中的实体关系
导航属性的理解: 指数据库的表所对应的实体类,除了要有每个字段所对应的属性之外,还应该有一个与之有关联的表的属性,一对一的关系就是关联表的类型,一对多的关系就是关联表的类型的ICollection的泛 ...
- 【记录】EF Code First 实体关联,如何添加、修改实体?
在使用 EF Code First 的时候,我们经常会对项目中的 Entry 进行一对多.多对多的映射配置,这时候就会产生主实体和子实体的概念,我们在添加.修改他们的时候,有时候会产生一些问题,比如添 ...
- Entity Framework 实体状态
从今天开始我们开始讲解EF中的实体状态和数据操作,这篇文章先讲解实体状态. 我们通过前面的学习,知道EF通过上下位负责跟踪实体的状态,实体状态的位置是在命名空间 System.Dat.Entity 里 ...
随机推荐
- C++类实现最大数的输出
Description 判断整数的大小,输入n个数,找出最大的数并输出. Input 有多组测试实例,输入n,并输入n个数. Output 输出的最大的数,每个输出结果占一行. Sample Inpu ...
- jquery 判断当前上传文件大小限制上传格式 搭配thinkphp实现上传即预览(模拟异步上传)
在web开发中,最纠结的一项就是文件上传,最近由于项目需要前后摸索了四天在这里分享给大家.如有不足,望指出!! 前台:jquery.easyui.html 后台:thinkphp 主要涉及语言:jqu ...
- web项目启动,运行方法
1.显示器(Listener) web文件加入 <listener> <listener-class>cn.ro.common.InitListener</li ...
- hibernate它5.many2one单向
关系数据库表之间的关系: 1 正确 1 1 正确 许多 许多 正确 许多 表间关系设计 基于主键关联 基于外键关联 基于中间表 1 对 1关系实现: 基于主键关联 基于外键关联 基于中间表 1 对 多 ...
- Ozmosis实现BIOS直接启动Yosemite,基本完美
我的主板是 技嘉 z97 d3h,共享一下我制作好的 Ozmosis
- windows下VC界面 DIY系列1----写给想要写界面的C++程序猿的话
非常早就想写关于C++ UI开发的一系列博文,博客专栏刚审核通过,就立即開始刷博文,不能辜负自己的一番热血,我并非写界面的高手,仅仅想通过写博文提高我自己的技术积累,也顺便帮助大家解决界面开发的瓶颈. ...
- Cocos2d-x 3.0final 终结者系列教程04-引擎架构分析
从前,有一个跟我来Android学生,总是问我: 沉老师,为什么Android的形式被称为Activity,为什么要onCreate方法写setContentView(R.layout.main)? ...
- 一个非常有用的函数——COALESCE
原文:一个非常有用的函数--COALESCE 很多人知道ISNULL函数,但是很少人知道Coalesce函数,人们会无意中使用到Coalesce函数,并且发现它比ISNULL更加强大,其实到目前为止, ...
- Android 实现蘑菇街购物车动画效果
版本号:1.0 日期:2014.8.6 版权:© 2014 kince 转载注明出处 使用过蘑菇街的用户基本上都知道有一个增加购物车的动画效果,此处不详细描写叙述想知道的能够去下载体验一下. 1 ...
- java验证手机号码是否合法
公司开发新功能须要验证手机号码,遂自己写了个出来,暂仅仅支持中国大陆手机号验证.如有不妥之处,还望大家指教,感激不尽! /** * 验证是否是正确合法的手机号码 * * @param telephon ...