關於Entity Framework更新的幾種方式以及可能遇到的問題(附加類型“Model”的實體失敗,因為相同類型的其他實體已具有相同的主鍵值)在使用 "Attach" 方法或者將實體的狀態設置為 "Unchanged" 或 "Modified" 時如果圖形中的任何實體具有沖突鍵值,則可能會發生上述行為


在日常使用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();
        }
    }
View Code

第一種更新方式,先通過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;
}

再次運行程序,沒有問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM