将 DTO 传递到服务层以进行 CRUD 操作

Passing DTO's to service layer for CRUD operations

我正在开发 ASP.NET MVC Web 应用程序。 我当前的架构如下:

Presentation Layer <--> Service Layer <--> Data Access Layer

数据访问层包含 EF 实体模型。 服务层从数据访问层和 returns DTO 检索 EF 实体模型。 表示层从服务层检索 DTO,并将 returns ViewModels 检索到视图。

我的问题是 class 我应该将什么传递给驻留在服务层中的创建和更新函数。例如:

实体模型:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }     
    public string LastName { get; set; }            
    public int UserTypeId { get; set; }

    public virtual UserType UserType { get; set; }
}

public class UserType
{
    public int Id { get; set; }
    public string Name { get; set; }                

    public virtual UserType UserType { get; set; }
}

DTO:

public class UserDTO
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }                
    public int UserTypeId { get; set; }

    //Note this "extra" field
    public string UserTypeName { get; set; }        
}

服务层函数:

public class UserService: IUserService
{
    public UserDTO GetUser(int userId)
    {
        //The UserType.Name is used a lot, so I'd rather include it in this one db call 
        //rather than use a separate db call to get the name based on the UserTypeId

        return _dbContext.Users.Where(u => u.Id == userId)
                   .Select(u => new UserDTO 
                   {
                       Id = u.Id,
                       FirstName = u.FirstName,
                       LastName = u.LastName,
                       UserTypeId = u.UserTypeId,

                       UserTypeName = u.UserType.Name
                   }
                   .First();
    }

    //??
    public void EditUser(UserDTO userDto)
    {
        //Should I use this? Or EditUser(EditUserDTO editUserDto)...    
    }

    //??
    public void EditUser(EditUserDTO editUserDto)
    {
        //Should I use this? Or EditUser(UserDTO userDto)...   
        //Note EditUserDTO looks like UserDTO but does not have UserTypeName 
    }
}

您会发现我的困惑在于 class 用作 EditUser(...) 的参数。

一些想法:

  1. 我可以让 DTO 与实体模型完全匹配,但是使用 DTO 有什么意义呢?
  2. 我可以将 UserTypeDTO class 作为 UserDTO 的 属性 而不是 "flat" DTO。我认为这会使事情更清楚一些,但在调用 EditUser(UserDTO) 时仍然不需要设置它。 附带问题:关于 D​​TO 是否应该 "flat" 是否有任何最佳实践?
  3. 还有其他想法吗...?

感谢您的帮助!!

我建议对 Get 和 Edit 操作使用单独的 DTO 定义。这样一来,消费者就不可能尝试设置他们不应该设置的内容。所以我会说对 EditUser 方法使用 EditUserDTO

更新

为我的回答添加更多上下文。

使用 DTO 的想法是抽象出您的底层 DAL。通常有更多的数据存储在您的数据层中,这些数据不是从您的服务层 return 编辑的,或者您的实体可能不具有您想要发送回调用者的相同结构,因此通过创建 DTO 您能够隐藏它。这也为您提供了一个选项,您可以更改 DAL 并保持服务层的 public 合同不变,这样当您在内部更改某些内容时,消费者不必重新编写他们的代码。

DTO 可以是平面的或具有层次结构的。这实际上取决于保持 DTO 平坦还是具有层次结构是否有意义。以您的示例 UserDTO 为例,我会说除非您要 return UserDTO 中的 UserTypes 树,否则您应该将其保留为简单的 "flat" DTO。