[.net] 엔티티 프레임 워크 엔티티의 변경 실행 취소

이것은 사소한 질문 일 수 있지만 : ADO.NET 엔터티 프레임 워크가 자동으로 변경 사항 (생성 된 엔터티에서)을 추적하고 따라서 원래 값을 유지하므로 엔터티 개체에 대한 변경 사항을 롤백 할 수있는 방법은 무엇입니까?

사용자가 그리드보기에서 “고객”엔터티 집합을 편집 할 수있는 양식이 있습니다.

이제 “수락”과 “되돌리기”버튼이 두 개 있습니다. “수락”을 클릭하면 호출 Context.SaveChanges()하면 변경된 개체가 데이터베이스에 다시 기록됩니다. “되돌리기”를 클릭하면 모든 개체가 원래 속성 값을 가져 오기를 원합니다. 그 코드는 무엇입니까?

감사



답변

EF에는 되돌리기 또는 변경 취소 작업이 없습니다. 각 엔티티가 ObjectStateEntry에서 ObjectStateManager. 상태 항목에는 원래 값과 실제 값이 포함되어 있으므로 원래 값을 사용하여 현재 값을 덮어 쓸 수 있지만 각 엔터티에 대해 수동으로 수행해야합니다. 탐색 속성 / 관계의 변경 사항을 무시하지 않습니다.

“변경 사항을 되 돌리는”일반적인 방법은 컨텍스트를 삭제하고 엔티티를 다시로드하는 것입니다. 다시로드하지 않으려면 엔티티의 복제본을 만들고 새 개체 컨텍스트에서 해당 복제본을 수정해야합니다. 사용자가 변경 사항을 취소해도 원래 엔티티가 유지됩니다.


답변

DbContext의 ChangeTracker에서 더티 항목을 쿼리합니다. 삭제 된 항목 상태를 변경되지 않음으로 설정하고 추가 된 항목을 분리됨으로 설정합니다. 수정 된 항목의 경우 원래 값을 사용하고 항목의 현재 값을 설정하십시오. 마지막으로 수정 된 항목의 상태를 변경되지 않음으로 설정합니다.

public void RollBack()
{
    var context = DataContextFactory.GetDataContext();
    var changedEntries = context.ChangeTracker.Entries()
        .Where(x => x.State != EntityState.Unchanged).ToList();

    foreach (var entry in changedEntries)
    {
        switch(entry.State)
        {
            case EntityState.Modified:
                entry.CurrentValues.SetValues(entry.OriginalValues);
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Deleted:
                entry.State = EntityState.Unchanged;
                break;
        }
    }
 }


답변

dbContext.Entry(entity).Reload();

MSDN에 동의 :

데이터베이스의 값으로 속성 값을 덮어 쓰는 데이터베이스에서 엔터티를 다시로드합니다. 이 메서드를 호출 한 후 엔티티는 Unchanged 상태가됩니다.

요청을 통해 데이터베이스로 되 돌리면 몇 가지 단점이 있습니다.

  • 네트워크 트래픽
  • DB 과부하
  • 증가 된 애플리케이션 응답 시간

답변

이것은 나를 위해 일했습니다.

dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);

item되돌릴 고객 엔티티는 어디에 있습니까 ?


답변

변경 사항을 추적하지 않는 쉬운 방법. 모든 엔티티를 보는 것보다 더 빠릅니다.

public void Rollback()
{
    dataContext.Dispose();
    dataContext= new MyEntities(yourConnection);
}


답변

// Undo the changes of all entries. 
foreach (DbEntityEntry entry in context.ChangeTracker.Entries())
{
    switch (entry.State)
    {
        // Under the covers, changing the state of an entity from  
        // Modified to Unchanged first sets the values of all  
        // properties to the original values that were read from  
        // the database when it was queried, and then marks the  
        // entity as Unchanged. This will also reject changes to  
        // FK relationships since the original value of the FK  
        // will be restored. 
        case EntityState.Modified:
            entry.State = EntityState.Unchanged;
            break;
        case EntityState.Added:
            entry.State = EntityState.Detached;
            break;
        // If the EntityState is the Deleted, reload the date from the database.   
        case EntityState.Deleted:
            entry.Reload();
            break;
        default: break;
    }
} 

그것은 나를 위해 일했습니다. 그러나 이전 데이터를 가져 오려면 컨텍스트에서 데이터를 다시로드해야합니다. 여기에 소스


답변

“이것은 나를 위해 일했습니다.

dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);

item되돌릴 고객 엔티티는 어디에 있습니까 ? “


SQL Azure에서 ObjectContext.Refresh를 사용하여 테스트를 수행했으며 “RefreshMode.StoreWins”는 각 엔터티에 대한 데이터베이스에 대한 쿼리를 실행하고 성능 누수를 유발합니다. Microsoft 설명서 ()를 기반으로 :

ClientWins : 개체 컨텍스트의 개체에 대한 속성 변경 사항이 데이터 소스의 값으로 대체되지 않습니다. 다음에 SaveChanges를 호출하면 이러한 변경 사항이 데이터 소스로 전송됩니다.

StoreWins : 개체 컨텍스트의 개체에 대한 속성 변경 사항이 데이터 소스의 값으로 바뀝니다.

.SaveChanges를 실행하면 데이터 소스에 “삭제 된”변경 사항이 커밋되기 때문에 ClientWins도 좋은 아이디어가 아닙니다.

생성 된 새 컨텍스트에서 쿼리를 실행하려고 할 때 컨텍스트를 삭제하고 새 컨텍스트를 만들면 “기본 공급자가 열릴 때 실패했습니다”라는 메시지와 함께 예외가 발생하기 때문에 아직 최선의 방법이 무엇인지 모르겠습니다.

문안 인사,

Henrique Clausing