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