Asp.net mvc 3 创建/更新场景中的部分模型验证

Asp.net mvc 3 创建/更新场景中的部分模型验证,asp.net-mvc-3,validation,Asp.net Mvc 3,Validation,我有一个由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; } } 然后我创建了一个用户模型,并应用数据注释来添加验证。

我有一个由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; }
}
然后我创建了一个用户模型,并应用数据注释来添加验证。我使用AutoMapper在用户和用户模型之间进行转换

我现在正尝试使用以下业务规则创建视图:

  • 创建用户时,“创建”和“上次修改”字段不应出现在UI中,但应在将模型保存在存储库中之前对其进行设置
  • 编辑用户时,创建的字段和LastModified字段不应出现在UI中,但创建的字段应保持不变,并且应在将模型保存到存储库中之前更新LastModified字段
  • 编辑用户时,如果未触摸密码字段,则不会更改模型中的密码字段;如果密码字段包含值,则应使用该值更新模型

那么,如何在尽可能少的代码重复的情况下实现这一点呢?例如,我应该有一个EditUserModel和一个CreateUserModel,从一个基本UserModel继承,这个基本UserModel有两个相同的字段(Id、名称、密码)?任何一个模型是否都应该引用创建的/上次修改的?特别是,我如何处理密码更改要求?

对于前两个问题,在模型中创建的字段和最后修改的字段应定义为只读,或者根本不映射,您可以在数据库中使用INSERT和UPDATE触发器来设置其值

另一种可能是在数据上下文中调用方法,并在实体上调用相应的方法,以便在插入或更新之前设置这些属性的值

编辑用户时,如果未触摸密码字段,则 模型中的密码字段未更改;如果密码字段 包含一个值,该值应用于更新模型


您可以尝试在映射层处理此需求。

这是我通常处理这种情况的方式。对于视图模型,我只使用了一个,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);
更新时

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没有太多经验,因此此代码肯定可以优化)

这是一个仓促的代码,所有这些都可以改进,但让我告诉你为什么采用这种“复杂”的方法。首先,我们对层的职责有了更清晰的区分,视图模型处理显示和向控制器发回数据所需的所有操作,并且域模型没有与持久性模型(EF模型)混合。您可以非常轻松地更改密码散列技术,并在真正发生更改的地方处理创建/上次修改的内容。当您开始添加更多功能时,这种设计将使您更加轻松

主要目标是清晰性和可维护性,根据使用情况,您可以采取另一种方法,如通过命令更新用户(向存储库发送命令以更改名称或密码)


好了,我现在完成了:)

我想这就是我必须要做的。很遗憾,我不能使用AutoMapper来完成所有映射-我必须显式地设置值,包括您演示的在更改密码时更新密码的逻辑。
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);
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;


    }