使用Entity Framework更新多對多關係?

c# entity-framework entity-framework-core

我有一個多對多的連接表,有一個雙鍵(PersonId,RoleId)。為簡單起見,我在Person表中只有一個PersonId。此外,使用EF7,它還不支持EF6所具有的很多優點(例如通過導航屬性加入表時的隱含性)。

雖然我可以在SQLite中運行此查詢並且它沒有問題: update PersonRole set RoleId = 2 where PersonId = 1 ,我在EF中不能做同樣的事情:

var du = context.PersonsRoles.Where(p => p.PersonId == 1).First();
du.RoleId = 2;
context.PersonsRoles.Update(du);
context.SaveChanges(); //get an error here

錯誤是:“發生了未處理的異常:實體類型'PersonRole'上的屬性'RoleId'是密鑰的一部分,因此無法修改或標記為已修改。”

(以下評論中的ETA) - 我的模型是:

var du = context.PersonsRoles.Where(p => p.PersonId == 1).First();
du.RoleId = 2;
context.PersonsRoles.Update(du);
context.SaveChanges(); //get an error here

我找到了一個答案,其中包括刪除原始行(1,1)然後重新插入(1,2)的選項,但這對我來說似乎效率低下。這真的是修改關係的唯一方法嗎?

一般承認的答案

您試圖在一側修改多對多關係的密鑰。多對多關係在數據庫中表示,其中一個表保存關係中雙方的外鍵。

您嘗試執行的操作是嘗試更改對象的鍵,但引用仍保留在外鍵表中,從而導致違反約束 - 因為NN表中的值尚未更新。

EF7中不允許進行此更改。您應該使用SQL命令來執行此操作,而不是考慮多對多表更新。


熱門答案

您可以使用此擴展程序刪除未選中的內容並將新選擇的內容添加到列表中

    public static void TryUpdateManyToMany<T, TKey>(this DbContext db, IEnumerable<T> currentItems, IEnumerable<T> newItems, Func<T, TKey> getKey) where T : class
    {
        db.Set<T>().RemoveRange(currentItems.Except(newItems, getKey));
        db.Set<T>().AddRange(newItems.Except(currentItems, getKey));
    }

    public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKeyFunc)
    {
        return items
            .GroupJoin(other, getKeyFunc, getKeyFunc, (item, tempItems) => new { item, tempItems })
            .SelectMany(t => t.tempItems.DefaultIfEmpty(), (t, temp) => new { t, temp })
            .Where(t => ReferenceEquals(null, t.temp) || t.temp.Equals(default(T)))
            .Select(t => t.t.item);
    }

使用它看起來像這樣

    public static void TryUpdateManyToMany<T, TKey>(this DbContext db, IEnumerable<T> currentItems, IEnumerable<T> newItems, Func<T, TKey> getKey) where T : class
    {
        db.Set<T>().RemoveRange(currentItems.Except(newItems, getKey));
        db.Set<T>().AddRange(newItems.Except(currentItems, getKey));
    }

    public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKeyFunc)
    {
        return items
            .GroupJoin(other, getKeyFunc, getKeyFunc, (item, tempItems) => new { item, tempItems })
            .SelectMany(t => t.tempItems.DefaultIfEmpty(), (t, temp) => new { t, temp })
            .Where(t => ReferenceEquals(null, t.temp) || t.temp.Equals(default(T)))
            .Select(t => t.t.item);
    }



許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因