2012-02-13 43 views
2

我有一個從現有的數據庫由EF生成的用戶模型:部分模型驗證在創建/更新方案

public class User 
{ 
public int Id { get;set; } 
public string Name { get;set; } 
public string Password { get;set; } 
public DateTime Created { get;set; } 
public DateTime LastModified { get;set; } 
} 

我已經然後創建一個的usermodel和應用數據的註釋添加驗證。我使用AutoMapper在User和UserModel之間進行轉換。

現在我試圖創建視圖,具有以下業務規則:

  • 創建一個用戶,在創建和上次更改領域不應該出現在用戶界面,但他們都應該事先設定該模型被保存在存儲庫中;
  • 編輯用戶時,創建和LastModified字段不應該出現在用戶界面中,但創建的字段應保持不變,LastModified字段應在模型保存在存儲庫之前更新;
  • 編輯用戶時,如果密碼字段未被觸摸,那麼模型中的密碼字段不會改變;如果密碼字段包含值,則應該使用該值來更新模型。

那麼我該如何實現這一點,儘可能少的代碼重複?例如,我是否應該有一個EditUserModel和一個CreateUserModel,繼承自一個基本的UserModel,它具有兩個(Id,Name,Password)共有的字段?任何一個模型是否都有對Created/LastModified的引用?特別是,我如何處理密碼更改要求?

回答

2

這是我通常如何處理這種情況。對於視圖模型,我只使用了一個,EditUserModel,因爲它實際上並沒有維護3個類,只有1-2個屬性是不同的,在我看來,視圖模型並不重要,我是隻是務實。在你的情況EditUserModel應該是這個樣子

public class EditUserModel 
{ 
    public int Id {get;set} //used when modifying user 
    public string Name {get;set;} 
    public string Password {get;set;} 
    public string ConfirmPassword {get;set;} //this is optionally 
} 

這種模式被傳遞給控制器​​和我個人使用DDD方法(作爲一種心態),並假設它看起來像這樣一個領域模型(創建用戶

var user= new Member(model.Name,new Password(model.Password,"a salt")); 
repository.Save(user); 

時當更新

它是基於代碼實際上,我使用)

public class Password 
{ 
    public Password(string value,string salt) 
    { 
     //you can apply basic validation rules if you want\\ 

     Hash=(salt+value).Sha256(); //a variant of hashing and an extension method 
     Salt=salt; 
    } 
    public string Hash {get;private set;} 
    public string Salt {get;private set;} 
} 

    public class Member 
{ 
    public Member(string name, Password pwd) 
    { 
     Name=name; 
     Password=pwd; 
     Created= DateTime.Now; 
    } 

    public Member(int id,DateTime created,string name,Password p) 
    { 
     Id = id; 
     Created = created; 
     _name = name; 
     _password = p; 
    } 
    public int Id { get; set; } 
    private string _name; 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      LastModified = DateTime.Now; 
      _name = value; 
     } 
    } 

    private Password _password; 
    public Password Password 
    { 
     get { return _password; } 
     set 
     { 
      _password = value; 
      LastModified = DateTime.Now; 
     } 
    } 

    public DateTime Created {get;private set;} 
    public DateTime LastModified {get;private set;} 
} 

第一次

var user= repository.GetUser(int id); 
user.Name=model.Name; 
if (!string.IsNullOrEmpty(model.Password)) user.Password= new Password(model.Password,"a salt"); 
repository.Save(user); 

在庫(注意,我不;噸有很多經驗與EF所以這段代碼肯定可以優化)

public void Save(Member user) 
{ 
using (var dc = new DbContext()) 
    { 

if (user.Id==0) 
    { 
    //do insert, all this can be handled via automapper 
    var u= new User(); 
    u.Name=user.Name; 
    u.Password=user.Password.Hash; 
    u.Created=user.Created; 
    u.LastModified=user.LastModifed; 
    dc.Users.Add(u); 
    dc.SaveChanges(); 
    user.Id=u.Id; 

    } 
else 
{ 
    //do edit 
    var u= dc.Users.First(d=>d.Id==user.Id); 
    //map values \\ 

    dc.Users.SaveChanges();// EF should detect if something was changed and save only changes 
    } 
} 
} 

    public Member GetUser(int id) 
    { 
    //get User from DbContext \\ 

     var m= new Member(id,user.Created,user.Name,new Password(user.Password,"my salt")); 
     return m; 


    } 

這是草率的代碼和所有可以改善,但讓我知道爲什麼這種'複雜'的方法。首先,我們在層的責任性之間有一個更明確的區別,視圖模型處理所有需要顯示並將數據發送回控制器,並且域模型不與持久性模型(EF模型)混合。你可以很容易地改變密碼散列技術,並且創建/最後修改的東西在真正發生變化的地方被處理。當您開始添加更多功能時,此設計將使您更容易。

主要目標是清晰和可維護性和dependeing上,你可以採取另一種方法像通過命令更新用戶(發送到庫中的命令來更改名稱或密碼)

好的,我使用現在完成:)

+0

我認爲這將是我必須做的。這只是一個恥辱,我不能使用AutoMapper來完成所有映射 - 我必須明確設置這些值,包括更改密碼時演示的邏輯。 – 2012-02-15 00:37:21

1

對於前兩個問題,創建和LastModified字段應定義爲只讀模型或根本不映射,您可以在數據庫中使用INSERT和UPDATE觸發器來設置它們的值。

另一種可能性是在您的數據上下文中調用override the SaveChanges方法,並在您的實體上調用相應的方法以便在插入或更新之前設置這些屬性的值。

編輯用戶時,如果密碼字段沒有被觸摸,那麼模型中的密碼字段不會被改變;如果密碼字段 包含一個值,則應使用該值來更新模型。

您可以嘗試在映射層處理此需求。