项目中不同层次的模型

3

最近我被“模型”搞糊涂了。假设我们在数据库中有一个名为“Users”的表,其中包含4个列,在数据层面我有一个对应的“User”模型。

namespace MyProject.Data
{
    public class User
    {
         public int Id { get; set; }
         public string UserName { get; set; }
         public string Password { get; set; }
         public int UserType { get; set; }
    }
}

在用户注册页面中,通常我会使用一个名为“User”(或您可以将其命名为UserRegistration)的视图模型。
namespace MyProject.Web
{
    public class User
    {
        public string UserName { get; set; }
        public string PlainTextPassword { get; set; }
    }
}

此外,我们可能有一个用户个人资料页面,对应的视图模型名为“User”或“UserProfile”,它们具有非常相似的属性(但不完全相同)。 第一个问题:上述用户模型是相似的,正确的设计方式是什么?
  1. 将它们分别放在不同的独立类中。这是我目前正在做的事情,但一些属性是共同的,我需要手动设置值(或使用类似AutoMapper的工具)。
  2. 在它们之间进行共享/继承。看起来“共同属性”得到了共享,在不同的“User”模型中没有“UserName”属性。然而,在注册页面的视图模型中却很奇怪,因为它有名为“Password”和“PlainTextPassword”的属性,甚至还有“UserType”,但实际上只设置了UserName和PlainTextPassword。
[HttpPost]
public ActionResult Register(User user)
{
    //only user.UserName and user.PlainTextPassword are useful
    //however you will have user.Password, user.UserType with default values
    //it even breaks the validation if you use ModelState.IsValid
}

看起来选项1更好?如果我错了或者你有其他想法,请纠正我。接下来基于选项1又出现了另一个问题。

第二个问题 我们有MyProject.Web.User作为视图模型和MyProject.Data.User作为数据模型。注册页面将一个MyProject.Web.User实例发送到我的控制器,最终我需要通过MyProject.Data.User将其保存到数据库中。应该是这样的:

//the controller in the web project
[HttpPost]
public ActionResult Register(User user)
{
     UserManager.Register(user.UserName, user.PlainTextPassword);
     //blabla
}

//UserManager in the business layer
public void Register(string userName, string plainTextPassword)
{
     //validation
     //set properties to MyProject.Data.User
     //save the changes to db (probably via EF)
}

如果添加更多的属性,例如 string address, string mobile,你会发现 UserManager.Register 的签名变得越来越长。我认为这里需要一个“用户”模型。MyProject.Web.User位于Web中,因此不能在 UserManager 中使用它。而 MyProject.Data.User 位于数据层,如果我们在这里使用 MyProject.Data.User,则 MyProject.Web 项目需要添加对 MyProject.Data 的引用,但是当前的引用关系是 UI->Core(业务逻辑)->Data。那么正确的设计是什么呢?

2个回答

1
这是我过去使用的方法。
在您的情况下,我会创建一个名为“User”的实体(在另一个项目中 - 可能称为Entities或Models)。然后在我的UI层中,我会创建一堆特定于视图的ViewModels(当然,您可以拥有一些共享基本ViewModel的视图),例如像这样的东西:
// This goes in MyProject.Web/ViewModels ...

public abstract class UserSecurityViewModel {
    // stuff that is shared between the other ViewModels
    public string Username { get; set; }
    public string Password { get; set; }
    // you get the idea ...
}

public class RegistrationViewModel : UserSecurityViewModel {
    // Registration specific properties
    public string Email { get; set; }
    // more ...
}

public class LoginViewModel : UserSecurityViewModel {
    // you don't need the email here ...
    public bool RememberMe { get; set; }
}

当然,我会使用类似于 AutoMapper 的工具来在视图模型和模型之间进行映射(在你的情况下是 User)。
例如:
[HttpPost]
public ActionResult Register(RegistrationViewModel viewModel) {
   User user = viewModel.ToUser(); // <-- this is an AutoMapper helper

   // now pass that to your business logic layer and do magic
   _userManager.Register(user);
}

我希望我的话说得通(并且我没有误解你)。


1

您可以使用视图模型模式解决您的问题。它只是一个类,您可以将其传递给视图以进行显示或表单提交。

namespace MyProject.Web
{
    public class UserViewModel
    {
        public string UserName { get; set; }
        public string PlainTextPassword { get; set; }
    }
}

然后你的User类可以放在一个单独的项目中(你可以称之为Entity),并且可以在Web项目和Data项目中引用它。
然后在你的控制器中,你可以将ViewModel映射到Model(你可以在这里使用Automapper),创建User对象并将其传递给Data层。
[HttpPost]
public ActionResult Register(UserViewModel userViewModel)
{
    User user = // map UserViewModel to User and get user object.
    // pass user object to data layer.
    _userService.Register(user);
}

既然你已经有了对 Entity 项目的引用,那么你可以在数据层中使用同一个 User 类。

public void Register(User user)
{

}

谢谢!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接