This topic will cover how to add and attach entities to a context and how Entity Framework processes these during SaveChanges. Entity Framework takes care of tracking the state of entities while they are connected to a context, but in disconnected or N-Tier scenarios you can let EF know what state your entities should be in. The techniques shown in this topic apply equally to models created with Code First and the EF Designer.
这篇文章将会涵盖如何新增、附加Entity(实体)到Context(上下文)以及Entity Framework在SaveChanges(保存)时是如何工作的。当Entity连接到一个Context的时候,Entity Framework负责跟踪Entity的状态,但但一旦断开连接或在N层结构你应该让EF知道你的Entity处于什么状态。这篇文章的技巧应用也适用于通过Code First以及EF Designer创建Models(模型)。
实体状态及保存变动
- 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
Entity状态有5个,分别是:
- Added(新增):entity将会被context跟踪,但是还没有新增到数据库
- Unchanged(未变动):entity已经存在数据库并且会被context跟踪,entity的属性值与数据库中一致,没有变动。
- Modified(修改):entity已经存在数据库并且会被context跟踪,entity的属性值被修改了。
- Deleted(删除):entity已经存在数据库并且会被context跟踪,但是已经被标记将在下一次savechanges(保存变动)的时候要从数据库中删除。
- Detached(分离的):entity不会被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.
当entity处于不同的状态时,SaveChanges(保存变动)做出不同的动作:
- SaveChanges不会变动未变动的entity。当entity处于未变动状态时,将不会向数据库发送Update指令
- 新增的entity将会在数据库中插入记录,返回之后变为未变动状态
- 修改的entity将会在数据库中修改记录,返回之后变为未变动状态
- 删除的entity将会在数据库中删除记录,返回之后变为分离状态
The following examples show ways in which the state of an entity or an entity graph can be changed.
接下去的实例将展示entity或entity graph(实体图表)的状态是如何变动的。
在上下文中新增实体
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:
在context(上下文)中新增entity(实体)是通过调用DbSet的Add方法。这将entity设置为Added状态,意味着实体将会在下一次SaveChanges调用的时候被插入到数据库中。
1 using (var context = new BloggingContext()) 2 { 3 var blog = new Blog { Name = "ADO.NET Blog" }; 4 context.Blogs.Add(blog); 5 context.SaveChanges(); 6 }
Another way to add a new entity to the context is to change its state to Added. For example:
另一种写法为:
1 using (var context = new BloggingContext()) 2 { 3 var blog = new Blog { Name = "ADO.NET Blog" }; 4 context.Entry(blog).State = EntityState.Added; 5 context.SaveChanges(); 6 }
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:
最后,你也可以通过在一个已经被context跟踪的entity上新增entity。这将会通过合集属性或设置引用属性到另一个entity来指向这个新的entity。例如:
1 using (var context = new BloggingContext()) 2 { 3 // Add a new User by setting a reference from a tracked Blog 4 var blog = context.Blogs.Find(1); 5 blog.Owner = new User { UserName = "johndoe1987" }; 6 7 // Add a new Post by adding to the collection of a tracked Blog 8 var blog = context.Blogs.Find(2); 9 blog.Posts.Add(new Post { Name = "How to Add Entities" }); 10 11 context.SaveChanges(); 12 }
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 be added to the context and will be inserted into the database the next time that SaveChanges is called.
【注意】以上例子,如果新增的entity是被引用到另一个还未被跟踪的entity上,这个新的entity还是会被新增到context上,并且在下次SaveChanges方法调用的时候插入到数据库中。
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:
如果你有一个已经在数据库中存在的,但是并未被现有的context跟踪的实体,你可以告诉context通过DbSet的Attach方案来跟踪这个entity。这个entity在context中将会被设置为未变动状态。例如:
1 var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; 2 3 using (var context = new BloggingContext()) 4 { 5 context.Blogs.Attach(existingBlog); 6 7 // Do some more work... 8 9 context.SaveChanges(); 10 }
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.
【注意】如果没有对附加的entit进行任何其他的操作,当调用SaveChanges方法时,数据库将不会有任何修改。这是因为entity处于未修改状态。
Another way to attach an existing entity to the context is to change its state to Unchanged. For example:
另一种写法:
1 var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; 2 3 using (var context = new BloggingContext()) 4 { 5 context.Entry(existingBlog).State = EntityState.Unchanged; 6 7 // Do some more work... 8 9 context.SaveChanges(); 10 }
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.
【注意】在以上例子中,如果附加的entity是引用到另一个未被跟踪的entity上,这个新的entity将会附加在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:
如果你有一个已经在数据库中存在的,但是已经做了修改的entity,你应该告诉context附加这个entity并设置状态为修改的。例如:1 var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; 2 3 using (var context = new BloggingContext()) 4 { 5 context.Entry(existingBlog).State = EntityState.Modified; 6 7 // Do some more work... 8 9 context.SaveChanges(); 10 }
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.
当你变更状态为修改的,entity的所有属性将会被标记为修改的,并且当SaveChanges方法被调用时,所有属性值都会传递给数据库。
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.
【注意】当entity被附加在一个未被跟踪的entity上时,这个新的entity将会附加在context上并设置为未变更状态,——他们不会被自动修改。如果你有数个entity需要标记为修改状态,你应该单独设置每一个entity为修改状态
You can change the state of an entity that is already being tracked by setting the State property on its entry. For example:
你可以通过设置State属性来变更被跟踪的entity状态,例如:
1 var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; 2 3 using (var context = new BloggingContext()) 4 { 5 context.Blogs.Attach(existingBlog); 6 context.Entry(existingBlog).State = EntityState.Unchanged; 7 8 // Do some more work... 9 10 context.SaveChanges(); 11 }
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.
【注意】在已经被跟踪的entity上新增或附加一个新的entity也将会改变entity的状态。例如,在一个处于新增状态的entity上附加一个新的entity将会改变他们的状态为未修改
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:
应用的通常模式为新增一个新的eneity(在数据库中为插入[insert语句]),或者是附加一个已经存在的的eneity并根据其主键的值将其标记为修改的(在数据库中为修改[update语句])。例如,当使用数据库自生成的int主键时,通常0表示为新增,非零表示为已存在的数据。这个模式可以通过核查主键的值来设置entity的状态实现,例如:
1 public void InsertOrUpdate(Blog blog) 2 { 3 using (var context = new BloggingContext()) 4 { 5 context.Entry(blog).State = blog.BlogId == 0 ? 6 EntityState.Added : 7 EntityState.Modified; 8 9 context.SaveChanges(); 10 } 11 }
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.
【注意】当你变更状态为修改的,entity的所有属性将会被标记为修改的,并且当SaveChanges方法被调用时,所有属性值都会传递给数据库。