在日常使用Entity Framework中,數據更新通常會用到。下面就簡單封裝了一個DBContext類
public partial class EFContext<T> : DbContext where T : class { public EFContext(): base("name=MyConnectionString") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.SetInitializer<EFContext<T>> (null); modelBuilder.Configurations.Add(new MemberMap()); modelBuilder.Configurations.Add(new RoleMap()); base.OnModelCreating(modelBuilder); } public DbSet<T> Table { get; set; } public IQueryable<T> GetList(Expression<Func<T,bool>> where) { return this.Table.Where(where); } public void Update(T entity) { if (entity == null) { throw new ArgumentException("entity"); } this.SaveChanges(); } }
第一種更新方式,先通過Entity Framework從數據庫中查找出一條記錄(實體對象),然后修改實體對象的各個屬性,最后調用Update方法
static void Main(string[] args) { EFContext<Member> memberContext = new EFContext<Member>(); var members = memberContext.GetList(m => true).ToList(); var model = members.Find(m => m.Id == 3); //第一種更新方式 model.Name = "豬八戒"; model.Delete = false; memberContext.Update(model); Console.ReadKey(); }
運行程序前:

運行程序后:

上面的方式可以修改為下面方式,DbContext封裝類中Update可以修改為如下的形式:
public void Update(T entity) { if (entity == null) { throw new ArgumentException("entity"); } this.Table.Attach(entity); this.Entry(entity).State = EntityState.Modified; this.SaveChanges(); }
static void Main(string[] args) { EFContext<Member> memberContext = new EFContext<Member>(); var members = memberContext.GetList(m => true).ToList(); var model = members.Find(m => m.Id == 3); //第一種更新方式 model.Name = "沙師弟"; model.Delete = true; memberContext.Update(model); Console.ReadKey(); }
運行前:

運行后:

第二種方式是new一個對象,這個對象各個屬性賦值,主鍵Id與數據庫某條已存在的記錄的Id相同
static void Main(string[] args) { EFContext<Member> memberContext = new EFContext<Member>(); var members = memberContext.GetList(m => true).ToList(); //var model = members.Find(m => m.Id == 3); ////第一種更新方式 //model.Name = "沙師弟"; //model.Delete = true; //memberContext.Update(model); //第二種方式 Member entity = new Member(); entity.Id = 3; entity.Name = "李小龍"; entity.Password = "lixiaolong"; entity.Delete = false; entity.RoleId = 3; memberContext.Update(entity); Console.WriteLine("update complete."); Console.ReadKey(); }
運行程序,會拋出異常。

附加類型“Core.Member”的實體失敗,因為相同類型的其他實體已具有相同的主鍵值。在使用 "Attach" 方法或者將實體的狀態設置為 "Unchanged" 或 "Modified" 時如果圖形中的任何實體具有沖突鍵值,則可能會發生上述行為。這可能是因為某些實體是新的並且尚未接收數據庫生成的鍵值。在此情況下,使用 "Add" 方法或者 "Added" 實體狀態跟蹤該圖形,然后將非新實體的狀態相應設置為 "Unchanged" 或 "Modified"。
因為Attach的實體對象是通過new創建的,而不是通過Entity Framework從數據庫中獲取的,但實例的主鍵對應數據在數據庫中存在,該實例而不存在於DBContext上下文中,嘗試Attach會拋出異常。通過監視可以看到是未附加到DbContext中

修改Update方法如下:
public void Update(T entity) { if (entity == null) { throw new ArgumentException("entity"); } if (this.Entry(entity).State == EntityState.Detached) { HandleDetached(entity); } this.Table.Attach(entity); this.Entry(entity).State = EntityState.Modified; this.SaveChanges(); } private bool HandleDetached(T entity) { var objectContext = ((IObjectContextAdapter)this).ObjectContext; var entitySet = objectContext.CreateObjectSet<T>(); var entityKey = objectContext.CreateEntityKey(entitySet.EntitySet.Name, entity); object foundSet; bool exists = objectContext.TryGetObjectByKey(entityKey, out foundSet); if (exists) { objectContext.Detach(foundSet); //從上下文中移除 } return exists; }
再次運行程序,沒有問題

