Entity Framework를 사용하여 Many to Many 관계를 업데이트 하시겠습니까?

c# entity-framework entity-framework-core

문제

나는 이중 키 (PersonId, RoleId)를 사용하여 다 대 다수 조인 테이블을가집니다. 그리고 간단하게하기 위해 필자는 Person 테이블에 PersonId를 하나만 가지고 있습니다. 또한 EF7을 사용하여 EF6이 수행하는 장점을 아직 지원하지 않습니다 (예 : 탐색 속성을 통해 테이블을 조인 함).

반면 SQLite에서이 쿼리를 실행할 수 있고 아무런 문제없이 작동합니다 update PersonRole set RoleId = 2 where PersonId = 1update 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)을 삭제 한 다음 reinsert (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는 합법적입니까? 예, 이유를 알아보십시오.