Programing

엔티티 프레임 워크, 관련 개체 업데이트 문제

lottogame 2020. 12. 25. 08:56
반응형

엔티티 프레임 워크, 관련 개체 업데이트 문제


현재 Entity Framework의 최신 버전을 사용하는 프로젝트를 진행 중이며 해결할 수없는 문제를 발견했습니다.

기존 객체를 업데이트 할 때 다른 클래스에 대한 참조 인 속성이 나올 때까지 객체 속성을 상당히 쉽게 업데이트 할 수 있습니다.

아래 예제에는 다양한 속성을 저장하는 Foo라는 클래스가 있으며이 중 2 개는 다른 클래스의 인스턴스입니다.

public class Foo
{
     public int Id {get; set;}
     public string Name {get; set;}
     public SubFoo SubFoo {get; set}
     public AnotherSubFoo AnotherSubFoo {get; set}
}

아래 Edit()방법을 사용할 때 업데이트하려는 객체를 전달 Name하고 제대로 업데이트 할 수 있도록 관리 할 수 있지만 SubFoo의 속성을 변경하는 방법을 찾지 못했습니다. 예를 들어 SubFoo클래스의 속성이이고이 속성 Name이 변경되어 내 DB와에서 다른 newFoo경우 업데이트되지 않습니다.

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
        .Include(x => x.SubFoo)
        .Include(x => x.AnotherSubFoo)
        .Single(c => c.Id == newFoo.Id);

    var entry = context.Entry<Foo>(dbFoo);
    entry.OriginalValues.SetValues(dbFoo);
    entry.CurrentValues.SetValues(newFoo);

    context.SaveChanges();

    return newFoo;
}

어떤 도움이나 조언을 주시면 대단히 감사하겠습니다.

업데이트 : Slauma의 의견에 따라 방법을 다음과 같이 수정했습니다.

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
        .Include(x => x.SubFoo)
        .Include(x => x.AnotherSubFoo)
        .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);

    context.SaveChanges();

    return newFoo;
}

지금 실행할 때 오류가 발생합니다.

엔티티 유형 Collection`1은 현재 컨텍스트에 대한 모델의 일부가 아닙니다.

이 문제를 해결하기 위해 newFoo하위 클래스를 컨텍스트 에 연결하는 코드를 추가 했지만 ObjectManager이미 동일한 엔터티가 있다는 오류가 발생했습니다 .

동일한 키를 가진 개체가 ObjectStateManager에 이미 있습니다. ObjectStateManager는 동일한 키로 여러 개체를 추적 할 수 없습니다.


CurrentValues.SetValues 스칼라 속성 만 업데이트하고 관련 항목은 업데이트하지 않으므로 각 관련 항목에 대해 동일한 작업을 수행해야합니다.

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
    context.Entry(dbFoo.AnotherSubFoo).CurrentValues.SetValues(newFoo.AnotherSubFoo);

    context.SaveChanges();

    return newFoo;
}

관계가 완전히 제거되었거나 생성 된 경우 해당 사례도 명시 적으로 처리해야합니다.

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    if (dbFoo.SubFoo != null)
    {
        if (newFoo.SubFoo != null)
        {
            if (dbFoo.SubFoo.Id == newFoo.SubFoo.Id)
                // no relationship change, only scalar prop.
                context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
            else
            {
                // Relationship change
                // Attach assumes that newFoo.SubFoo is an existing entity
                context.SubFoos.Attach(newFoo.SubFoo);
                dbFoo.SubFoo = newFoo.SubFoo;
            }
        }
        else // relationship has been removed
            dbFoo.SubFoo = null;
    }
    else
    {
        if (newFoo.SubFoo != null) // relationship has been added
        {
            // Attach assumes that newFoo.SubFoo is an existing entity
            context.SubFoos.Attach(newFoo.SubFoo);
            dbFoo.SubFoo = newFoo.SubFoo;
        }
        // else -> old and new SubFoo is null -> nothing to do
    }

    // the same logic for AnotherSubFoo ...

    context.SaveChanges();

    return newFoo;
}

결국 Modified관계가 변경된 경우 연결된 엔터티의 상태 스칼라 속성도 설정해야합니다.

편집하다

귀하의 의견에 따르면 Foo.SubFoo실제로 컬렉션이고 참조 일뿐 아니라 관련 엔터티를 업데이트하려면 다음과 같은 것이 필요합니다.

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    // Update foo (works only for scalar properties)
    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);

    // Delete subFoos from database that are not in the newFoo.SubFoo collection
    foreach (var dbSubFoo in dbFoo.SubFoo.ToList())
        if (!newFoo.SubFoo.Any(s => s.Id == dbSubFoo.Id))
            context.SubFoos.Remove(dbSubFoo);

    foreach (var newSubFoo in newFoo.SubFoo)
    {
        var dbSubFoo = dbFoo.SubFoo.SingleOrDefault(s => s.Id == newSubFoo.Id);
        if (dbSubFoo != null)
            // Update subFoos that are in the newFoo.SubFoo collection
            context.Entry(dbSubFoo).CurrentValues.SetValues(newSubFoo);
        else
            // Insert subFoos into the database that are not
            // in the dbFoo.subFoo collection
            dbFoo.SubFoo.Add(newSubFoo);
    }

    // and the same for AnotherSubFoo...

    db.SaveChanges();

    return newFoo;
}

관련 엔터티를 업데이트하는 방법을 이해하는 데 도움이 되었기 때문에 아래 링크를 게시 할 것이라고 생각했습니다.

Updating related data with the entity framework in an asp net mvc application

NOTE: I did change the logic slightly that is shown in the UpdateInstructorCourses function to suit my needs.


You can also call the tables independently

MyContext db = new MyContext
// I like using asynchronous calls in my API methods 
var OldFoo = await db.Foo.FindAsync(id);
var OldAssociateFoo = db.AssociatedFoo;  
var NewFoo = OldFoo;
var NewAssociatedFoo = OldAssociatedFoo;

NewFoo.SomeValue = "The Value";
NewAssociatedFoo.OtherValue = 20;

db.Entry(OldFoo).CurrentValues.SetValues(NewFoo);
db.Entry(OldAssociatedFoo).CurrentValues.SetValues(NewAssociatedFoo);

await db.SaveChangesAsync();

ReferenceURL : https://stackoverflow.com/questions/13236116/entity-framework-problems-updating-related-objects

반응형