[C#] Entity Framework 5 레코드 업데이트

ASP.NET MVC3 환경에서 Entity Framework 5 내에서 레코드를 편집 / 업데이트하는 다양한 방법을 탐색했지만 지금까지 필요한 모든 상자를 선택하지는 않습니다. 이유를 설명하겠습니다.

장단점을 언급 할 세 가지 방법을 찾았습니다.

방법 1-원본 레코드로드, 각 속성 업데이트

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

찬성

  • 변경할 속성을 지정할 수 있습니다
  • 뷰는 모든 속성을 포함 할 필요는 없습니다

단점

  • 원본을로드 한 후 업데이트하기위한 데이터베이스의 2 x 쿼리

방법 2-원본 레코드로드, 변경된 값 설정

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

찬성

  • 수정 된 속성 만 데이터베이스로 전송됩니다

단점

  • 뷰는 모든 속성을 포함해야합니다
  • 원본을로드 한 후 업데이트하기위한 데이터베이스의 2 x 쿼리

방법 3-업데이트 된 레코드 첨부 및 상태를 EntityState.Modified로 설정

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

찬성

  • 업데이트 할 데이터베이스의 1 x 쿼리

단점

  • 변경할 속성을 지정할 수 없습니다
  • 보기에는 모든 속성이 포함되어야합니다

질문

너희들에게 내 질문; 이 목표를 달성 할 수있는 확실한 방법이 있습니까?

  • 변경할 속성을 지정할 수 있습니다
  • 조회수는 모든 속성 (예 : 비밀번호)을 포함 할 필요는 없습니다.
  • 업데이트 할 데이터베이스의 1 x 쿼리

나는 이것이 지적해야 할 사소한 일이라는 것을 알고 있지만 이것에 대한 간단한 해결책이 누락되었을 수 있습니다. 방법이 아니라면 우선합니다 😉



답변

당신이 찾고있는:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();


답변

나는 받아 들인 대답을 정말로 좋아합니다. 나는 이것에 접근하는 또 다른 방법이 있다고 생각합니다. 뷰에 포함하고 싶지 않은 속성 목록이 매우 짧으므로 엔터티를 업데이트 할 때 속성이 생략된다고 가정 해 봅시다. 이 두 필드가 비밀번호와 SSN이라고 가정 해 봅시다.

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;

db.SaveChanges();   

이 예에서는 사용자 테이블과보기에 새 필드를 추가 한 후에 비즈니스 로직을 그대로 둘 수 있습니다.


답변

foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();


답변

스캐 폴딩으로 생성 된 업데이트 방법과 비슷한 추가 업데이트 방법을 리포지토리 기본 클래스에 추가했습니다. 전체 개체를 “수정”으로 설정하는 대신 개별 속성 집합을 설정합니다. (T는 클래스 일반 매개 변수입니다.)

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

그리고 예를 들어

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

나는 데이터베이스 여행을 좋아한다. 그러나 속성 집합이 반복되는 것을 피하기 위해 뷰 모델 로이 작업을 수행하는 것이 좋습니다. 뷰 모델 검사기의 유효성 검사 메시지를 도메인 프로젝트로 가져 오는 것을 피하는 방법을 모르기 때문에 아직 수행하지 않았습니다.


답변

public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}


답변

옵션 목록에 추가하기 만하면됩니다. 데이터베이스에서 객체를 가져오고 Auto Mapper 와 같은 자동 매핑 도구를 사용 하여 변경하려는 레코드 부분을 업데이트 할 수도 있습니다.


답변

사용 사례에 따라 위의 모든 솔루션이 적용됩니다. 이것은 내가 보통하는 방법입니다 :

서버 측 코드 (예 : 배치 프로세스)의 경우 일반적으로 엔티티를로드하고 동적 프록시로 작업합니다. 일반적으로 배치 프로세스에서는 서비스가 실행될 때 어쨌든 데이터를로드해야합니다. 시간을 절약하기 위해 find 메소드를 사용하는 대신 데이터를 일괄로드하려고합니다. 프로세스에 따라 낙관적 또는 비관적 동시성 제어를 사용합니다 (일반적인 SQL 문으로 일부 레코드를 잠글 필요가있는 병렬 실행 시나리오를 제외하고는 항상 낙관적입니다). 코드와 시나리오에 따라 영향을 거의 0으로 줄일 수 있습니다.

클라이언트 측 시나리오의 경우 몇 가지 옵션이 있습니다.

  1. 뷰 모델을 사용하십시오. 모델에는 UpdateStatus (unmodified-inserted-updated-deleted) 속성이 있어야합니다. 사용자 조치 (삽입-업데이트-삭제)에 따라이 열에 올바른 값을 설정하는 것은 클라이언트의 책임입니다. 서버는 원래 값에 대해 db를 쿼리하거나 클라이언트가 변경된 행과 함께 원래 값을 서버에 보내야합니다. 서버는 원래 값을 첨부하고 각 행에 대해 UpdateStatus 열을 사용하여 새 값을 처리하는 방법을 결정해야합니다. 이 시나리오에서는 항상 낙관적 동시성을 사용합니다. 이것은 insert-update-delete 문만 수행하고 선택은 수행하지 않지만 그래프를 걷고 엔티티를 업데이트하려면 영리한 코드가 필요할 수 있습니다 (시나리오-응용 프로그램에 따라 다름). 매퍼는 CRUD 논리를 도울 수는 있지만 처리하지는 않습니다.

  2. 이 복잡성을 대부분 숨기는 breeze.js와 같은 라이브러리를 사용하고 (1에서 설명) 사용 사례에 맞게 조정하십시오.

그것이 도움이되기를 바랍니다.