2011-01-15 2 views
4

사용자를 업데이트하려는 UserRepository에 문제가 있습니다. 특정 필드가 업데이트되지 않도록하고 싶습니다 (예 : 암호가 지정되지 않은 경우). 예를 들어 뷰에서 사용자를 리포지토리의 서비스로 전달할 때 null 또는 빈 암호 문자열을 사용하여 사용자를 보냅니다. 이 null은 데이터베이스에 기록됩니다 (원하는 것은 아닙니다).저장소 패턴의 순수 POCO 항목 업데이트 문제

어떻게 이런 상황을 처리합니까?

도메인

public class User 
{ 
    public int UserId { get; set; } 

    public string Email { get; set; } 
    public string Password { get; set; } 
} 

public User Save(User user) 
    { 
     if (user.UserId > 0) 
     { 
      User dbUser = context.Users.FirstOrDefault(u => u.UserId == user.UserId); 
      //What do I do here? 
     } 
     context.Users.AddObject(user); 
     context.SaveChanges(); 
     return user; 
    } 

이 경우 말할 수 있습니다 저장소, 내 생각이 날은 Email을 변경할 수 있습니다, 그래서 Save()로 다시 전송됩니다 유일한 방법은 user.UserIduser.Email이고 user.Password은 null입니다. 필자의 경우 암호는 null을 허용해야하므로 데이터베이스에서 오류가 발생합니다.

답변

10

분리 POCO 시나리오 (업데이트 전에 DB에서 사용자를로드 할 수 없습니다) :

당신은 선택적 속성을 업데이트해야하는 말할 수있다 :

public User Save(User user)  
{   
    if (user.UserId == 0)   
    {    
     context.Users.AddObject(user);   
    } 
    else 
    { 
     context.Users.Attach(user); 
     ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(user); 
     entry.SetModifiedProperty("Email"); 
    } 

    context.SaveChanges();   
    return user;  
} 

또한 두 가지를 만들 수 있습니다 과부하가 걸리는 Save 방법입니다.

public User Save(User user)  
{   
    if (user.UserId == 0)   
    {    
     context.Users.AddObject(user);   
    } 
    else 
    { 
     context.Users.Attach(user); 
     context.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);   
    } 

    context.SaveChanges();   
    return user;  
} 

public User Save(User user, IEnumerable<Expression<Func<User, object>>> properties)  
{   
    if (user.UserId == 0)   
    {    
     context.Users.AddObject(user);   
    } 
    else 
    { 
     context.Users.Attach(user); 
     ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(user); 
     foreach(var selector in properties) 
     { 
      string propertyName = PropertyToString(selector.Body); 
      entry.SetModifiedProperty(propertyName); 
     } 
    } 

    context.SaveChanges();   
    return user;  
} 

// Doesn't work for navigation properties! 
private static string PropertyToString(Expression selector) 
{ 
    if (selector.NodeType == ExpressionType.MemberAccess) 
    { 
     return ((selector as MemberExpression).Member as PropertyInfo).Name; 
    } 

    throw new InvalidOperationException(); 
} 

두 번째 오버로드 이런 식으로 호출합니다 : 첫 번째는 두 번째 명시 적으로 선택 속성을 업데이트합니다, 전체 개체를 업데이트합니다

userRepository.Save(user, new List<Expression<Func<User, object>>> 
    { 
     u => u.Email 
    }); 

첨부 시나리오 (업데이트 전에 DB에서 사용자를로드합니다) :

이 업데이트를 수행하는 방법을 제어 할 수 있도록 위임을 받아 들일 당신의 저장 방법을 수정할 수 있습니다

을 당신은 확실히 대린의 게시물 및 업데이트에 대한 특별 ModelViews에 대해 생각해야 내 사례에도 불구하고,

var user = GetUpdatedUserFromSomewhere(); 
repository.Save(user, (dbUser, mergedUser) => 
    { 
     dbUser.Email = mergedUser.Email; 
    }); 

어쨌든 :

public User Save(User user, Action<User, User> updateStrategy)         
{         
    if (user.UserId > 0)         
    { 
     User dbUser = context.Users.FirstOrDefault(u => u.UserId == user.UserId); 
     updateStrategy(dbUser, user);                   
    }   
    else 
    {       
     // New object - all properties should be saved 
     context.Users.AddObject(user); 
    } 

    context.SaveChanges();         
    return user;        
} 

당신은 방법이 방법을 호출합니다.

+0

명시 적으로 개체를 업데이트하는 필드의 경우 왜 PropertyToString은 bool에서 작동하지 않습니까? –

+0

그 updateStrategy는 아름다움의 것입니다. 그것을 사랑해! 지금 저장소의 업데이트 메소드에이를 사용하고 있습니다. 호출 코드는 무엇을 업데이트해야하는지, 어떻게 업데이트 할지를 결정합니다. – Jez

1

보기 모델을 사용해야합니다. 뷰 모델은 뷰의 필요에 맞게 조정되고이 뷰에서 필요한 속성 만 포함하는 클래스입니다. 그래서 컨트롤러 액션은 다음과 같이한다 : 대신

[HttpPost] 
public ActionResult Update(UserViewModel model) { ... } 

:

[HttpPost] 
public ActionResult Update(User model) { ... } 

을 당신이보기 모델과 모델 사이에 매핑 할 수있는 컨트롤러 액션 내부. AutoMapper은이 작업을 단순화 할 수있는 훌륭한 도구입니다.

정말 조심해야하며 이렇게 모델을 노출시키지 마십시오. 항상보기와보기 모델을 사용하십시오. 모델에 IsAdministrator 부울 속성이 있는지 상상해보십시오.

+1

이것은 내가하는 일입니다. 이것에 의해, 패스워드 필드를 null에 갱신하려고하고있는 리포지터리 (repository)의 문제는 해결되지 않습니다. –

+0

이것은 훌륭한 조언이지만 저장소의 특정 필드에 대한 업데이트를 처리하는 방법을 보여주지는 않습니다. –

+0

나는 이것이 올바른 것이라고 생각하기 때문에이 답변을 투표했습니다 (이번에는 0으로 되돌립니다). 작업에서 사용자를 저장소에서 끌어 와서 필요한 변경 사항 만 적용한 다음 다시 유지할 수 있습니다. 이메일 주소를 업데이트하기위한 조치 만 취한 상태이므로 업데이트가 필요한 것입니다. –

0

사용 권한을 부여 할 수 있습니까?

public User Save(User user) 
    { 
     if (user.UserId > 0) 
     { 
      User dbUser = context.Users.FirstOrDefault(u => u.UserId == user.UserId); 
      //What do I do here? 
      dbUser.Email = user.Email 
      user = dbUser; 
     } 
     else 
     { 
      context.Users.AddObject(user); 
     } 
     context.SaveChanges(); 
     return user; 
    } 
+0

업데이트 할 필드를 확인해보십시오. if (! string.IsNullOrEmpty (user.Email)), if (! string.IsNullOrEmpty (user.Password)) 등 –