Entity Framework Tutorial Basics(27):Update Entity Graph
2016-07-07 10:28
197 查看
Update Entity Graph using DbContext:
Updating an entity graph in disconnected scenario is a complex task. It is easy to add a new entity graph in disconnected mode, but to update an entity graph needs careful design consideration.The problem in updating an entity graph in the disconnected scenario, is that the context doesn't know what operation was performed on it at the client side. As per the following figure, the new context doesn't know the state of each entity:
We need to identify the states of each entity in the entity graph, before calling the SaveChages() method of context. There are different patterns to identify entity state, which we need to consider in designing data layer with Entity Framework.
Patterns of Identifying Entity State in disconnected scenario:
There are several ways (some shown below) to identify an entity state in disconnected scenario:Using PrimaryKey (Id) property of an entity
Having state property in entity set
Note: You can create your own design to identify an entity state based on your architecture. This is just for learning purposes.
1) Using PrimaryKey property of an entity:
You can use the PrimaryKey (Id) property of each entity to determine its entity state. However, you have to decide which of the following architectural rule to use:Each type of entity must have Id property (PK)
Default value of Id property should be 0
As you can see in the figure shown above, the client fetches the Standard and Teacher entity graph and does some operations on it and then sends it to Context 2 to save the changes.
In the disconnected scenario, context2 doesn't know the state of each entity. It has to determine the state of the Standard entity by using StandardId and the state of the Teacher entity by using TeacherId property. If StandardId and TeacherID value is zero, that means it is a new entity and if it is not zero then it is a modified entity.
In the above figure, Standard, Teacher 1, and Teacher 2 have a non-zero Id property value so they are marked as Modified and Teacher 3 Id is zero so it is marked as Added.
The code snippet shown below uses Id property to mark an entity state:
Standard disconnectedStandard = null; using (var context = new SchoolDBEntities()) { context.Configuration.ProxyCreationEnabled = false; disconnectedStandard = context.Standards.Where(s => s.StandardId == 58).Include(s => s.Teachers).FirstOrDefault<Standard>(); } //Update Standard in disconnected mode disconnectedStandard.StandardName = "Edited Standard Name"; //Update teachers collection by editing first teacher and adding new teacher disconnectedStandard.Teachers.ElementAt(0).TeacherName = "Edited Teacher Name"; disconnectedStandard.Teachers.Add(new Teacher() { TeacherName = "New Teacher", StandardId = disconnectedStandard.StandardId }); using (var newContext = new SchoolDBEntities()) { //mark standard based on StandardId newContext.Entry(disconnectedStandard).State = disconnectedStandard.StandardId == 0 ? EntityState.Added : EntityState.Modified; //mark teacher based on StandardId foreach (Teacher tchr in disconnectedStandard.Teachers) newContext.Entry(tchr).State = tchr.TeacherId == 0 ? EntityState.Added : EntityState.Modified; newContext.SaveChanges(); }
Advantages:
No need for extra coding/processing to determine entity state.
Good performance.
Disadvantages:
Every entity type needs to have an Id property. It cannot determine states of an entity that do not have Id property.
Cannot identify an Unchanged entity. It is set to Modified state even if the entity is not changed at all. So, there is an unnecessary database update statement for an unchanged entity.
Cannot handle delete entity scenario. It needs to handle deletion separately.
2) Having State property in every entity:
Another way to determine entity state is to have a State property in every entity type and set an appropriate state from the client side in disconnected mode. Then we just need to set the entity state as the state property of an entity object before calling SaveChanges of the new context.Example:
First of all, create an IEntityState interface with enum property called ObjectState:
interface IEntityObjectState { EntityObjectState ObjectState { get; set; } } public enum EntityObjectState { Added, Modified, Deleted, Unchanged }
Now, implement an IEntityObjectState in each entity class, e.g. Standard and Teacher entity, as shown below:
public partial class Standard:IEntityObjectState { public Standard() { this.Students = new HashSet<Student>(); this.Teachers = new HashSet<Teacher>(); } public int StandardId { get; set; } public string StandardName { get; set; } public string Description { get; set; } public virtual ICollection<Student> Students { get; set; } public virtual ICollection<Teacher> Teachers { get; set; } [NotMapped] public EntityObjectState ObjectState { get; set; } } public partial class Teacher:IEntityObjectState { public Teacher() { this.Courses = new HashSet<Course>(); } public int TeacherId { get; set; } public string TeacherName { get; set; } public Nullable<int> StandardId { get; set; } public virtual ICollection<Course> Courses { get; set; } public virtual Standard Standard { get; set; } [NotMapped] public EntityObjectState ObjectState { get; set; } }
Set the appropriate state in disconnected mode on client side:
Teacher existingTeacher = null; using (var context = new SchoolDBEntities()) { context.Configuration.ProxyCreationEnabled = false; existingTeacher = context.Teachers.FirstOrDefault<Teacher>(); } Standard disconnectedStandard = new Standard() { StandardName = "New Standard", ObjectState = EntityObjectState.Added }; existingTeacher.ObjectState = EntityObjectState.Modified; //add existing teacher(in db) to standard disconnectedStandard.Teachers.Add(existingTeacher); //add new standard disconnectedStandard.Teachers.Add(new Teacher() { TeacherName = "New teacher", StandardId = disconnectedStandard.StandardId, ObjectState = EntityObjectState.Added });
Set the entity state as per ObjectState before calling SaveChanges.
using (var newContext = new SchoolDBEntities()) { //check the ObjectState property and mark appropriate EntityState if (disconnectedStandard.ObjectState == EntityObjectState.Added) newContext.Entry(disconnectedStandard).State = System.Data.Entity.EntityState.Added; else if (disconnectedStandard.ObjectState == EntityObjectState.Modified) newContext.Entry(disconnectedStandard).State =System.Data.Entity.EntityState.Modified; else if (disconnectedStandard.ObjectState == EntityObjectState.Deleted) newContext.Entry(disconnectedStandard).State = System.Data.Entity.EntityState.Deleted; else newContext.Entry(disconnectedStandard).State = System.Data.Entity.EntityState.Unchanged; //check the ObjectState property of each teacher and mark appropriate EntityState foreach (Teacher tchr in disconnectedStandard.Teachers) { if (tchr.ObjectState == EntityObjectState.Added) newContext.Entry(tchr).State = System.Data.Entity.EntityState.Added; else if (tchr.ObjectState == EntityObjectState.Modified) newContext.Entry(tchr).State = System.Data.Entity.EntityState.Modified; else if (tchr.ObjectState == EntityObjectState.Deleted) newContext.Entry(tchr).State = System.Data.Entity.EntityState.Deleted; else newContext.Entry(tchr).State = System.Data.Entity.EntityState.Unchanged; } //save changes newContext.SaveChanges(); }
Advantages:
No need for extra coding/processing to determine the entity state
Handles Added, Modified, Deleted, and Unchanged states properly
No unnecessary update call for unchanged entities.
Disadvantage:
Need to set the appropriate states of each entity in disconnected mode. So there is a need to be extra careful in disconnected mode.
相关文章推荐
- 欢迎使用CSDN-markdown编辑器
- Oracle启动监听错误TNS-12555: TNS:permission denied
- Python+Eclipse+pydev环境搭建
- android 字体设置
- STL vector用法介绍
- SQL 数据库
- HTTPS和HTTP的区别
- 常用LaTeX公式字体设置及基元模板
- Spring三种注入IOC注入方式
- Mysql 慢查询和慢查询日志分析
- Mysql删除数据后磁盘空间未释放的解决办法【转】
- 导入spine使用
- mysql int(11)字段左边自动补零了
- javascript浏览器对象——History对象
- 构建在开源之上的商业软件市场持续成长
- mysql 查询copy to tmp table造成堵塞
- Qt控件使用
- 使用bootstrap typeahead插件实现输入框自动补全之问题及解决办法
- 【Nginx】入门熟悉
- Spring Boot(1),从最简单的开始