将 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(...) 的参数。
- 如果我使用
EditUser(UserDTO userDto)
,那么其他开发者会如何
知道他们不需要设置UserDTO.UserTypeName吗?他们
只需要设置 UserTypeId.
- 如果我使用
EditUser(EditUserDTO editUserDto)
,那么开发者就会知道
确切设置哪个信息(EditUserDTO 中的每个 属性)。但是需要额外 class 来维护、映射和使用。
一些想法:
- 我可以让 DTO 与实体模型完全匹配,但是使用 DTO 有什么意义呢?
- 我可以将 UserTypeDTO class 作为 UserDTO 的 属性 而不是 "flat" DTO。我认为这会使事情更清楚一些,但在调用 EditUser(UserDTO) 时仍然不需要设置它。 附带问题:关于 DTO 是否应该 "flat" 是否有任何最佳实践?
- 还有其他想法吗...?
感谢您的帮助!!
我建议对 Get 和 Edit 操作使用单独的 DTO 定义。这样一来,消费者就不可能尝试设置他们不应该设置的内容。所以我会说对 EditUser 方法使用 EditUserDTO
。
更新
为我的回答添加更多上下文。
使用 DTO 的想法是抽象出您的底层 DAL。通常有更多的数据存储在您的数据层中,这些数据不是从您的服务层 return 编辑的,或者您的实体可能不具有您想要发送回调用者的相同结构,因此通过创建 DTO 您能够隐藏它。这也为您提供了一个选项,您可以更改 DAL 并保持服务层的 public 合同不变,这样当您在内部更改某些内容时,消费者不必重新编写他们的代码。
DTO 可以是平面的或具有层次结构的。这实际上取决于保持 DTO 平坦还是具有层次结构是否有意义。以您的示例 UserDTO
为例,我会说除非您要 return UserDTO
中的 UserTypes 树,否则您应该将其保留为简单的 "flat" DTO。
我正在开发 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(...) 的参数。
- 如果我使用
EditUser(UserDTO userDto)
,那么其他开发者会如何 知道他们不需要设置UserDTO.UserTypeName吗?他们 只需要设置 UserTypeId. - 如果我使用
EditUser(EditUserDTO editUserDto)
,那么开发者就会知道 确切设置哪个信息(EditUserDTO 中的每个 属性)。但是需要额外 class 来维护、映射和使用。
一些想法:
- 我可以让 DTO 与实体模型完全匹配,但是使用 DTO 有什么意义呢?
- 我可以将 UserTypeDTO class 作为 UserDTO 的 属性 而不是 "flat" DTO。我认为这会使事情更清楚一些,但在调用 EditUser(UserDTO) 时仍然不需要设置它。 附带问题:关于 DTO 是否应该 "flat" 是否有任何最佳实践?
- 还有其他想法吗...?
感谢您的帮助!!
我建议对 Get 和 Edit 操作使用单独的 DTO 定义。这样一来,消费者就不可能尝试设置他们不应该设置的内容。所以我会说对 EditUser 方法使用 EditUserDTO
。
更新
为我的回答添加更多上下文。
使用 DTO 的想法是抽象出您的底层 DAL。通常有更多的数据存储在您的数据层中,这些数据不是从您的服务层 return 编辑的,或者您的实体可能不具有您想要发送回调用者的相同结构,因此通过创建 DTO 您能够隐藏它。这也为您提供了一个选项,您可以更改 DAL 并保持服务层的 public 合同不变,这样当您在内部更改某些内容时,消费者不必重新编写他们的代码。
DTO 可以是平面的或具有层次结构的。这实际上取决于保持 DTO 平坦还是具有层次结构是否有意义。以您的示例 UserDTO
为例,我会说除非您要 return UserDTO
中的 UserTypes 树,否则您应该将其保留为简单的 "flat" DTO。