我正在开发一个 ASP.NET 的MVC Web应用程序。 我当前的体系结构如下所示:
Presentation Layer <--> Service Layer <--> Data Access Layer
数据访问层包含 EF 实体模型。 服务层从数据访问层检索 EF 实体模型并返回 DTO。 表示层从服务层检索 DTO,并将视图模型返回到视图。
我的问题是关于我应该将哪个类传递给驻留在服务层中的创建和更新函数。例如:
实体模型:
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
}
}
你会看到我的困惑是用什么类作为 EditUser(... 的参数(。
- 如果我使用
EditUser(UserDTO userDto)
,那么其他开发人员将如何 知道他们不需要设置 UserDTO.UserTypeName?他们 只需要设置用户类型 ID。 - 如果我使用
EditUser(EditUserDTO editUserDto)
,那么开发人员就会知道 确切地要设置的信息(编辑用户DTO中的每个属性(。但它是一个额外的类来维护、映射和使用。
一些想法:
- 我可以让 DTO 与实体模型完全匹配,但是使用 DTO 有什么意义呢?
- 与其有一个"平面"DTO,我可以使用一个UserTypeDTO类作为UserDTO的属性。我认为这会让事情更清楚一些,但在调用 EditUser(UserDTO( 时仍然不需要设置它。附带问题:关于DTO是否应该是"扁平的",是否有任何最佳实践?
- 还有其他想法吗?
感谢您的帮助!!
我建议对获取和编辑操作使用单独的 DTO 定义。那么消费者就不可能试图设置他们不应该设置的东西。所以我会说对 EditUser 方法使用EditUserDTO
。
更新
为我的答案添加更多上下文。
使用 DTO 的想法是抽象出您的底层 DAL。数据层中通常存储了更多未从服务层返回的数据,或者您的实体可能与您想要发送回调用方的结构不同,因此通过创建 DTO,您可以将其隐藏起来。这也为您提供了更改 DAL 并保持服务层的公共协定不变的选项,以便使用者在内部更改某些内容时不必重写其代码。
DTO可以是平面的,也可以是有层次结构的。这实际上取决于保持DTO扁平化还是具有层次结构是否有意义。以你的例子UserDTO
,我会说,除非你要在UserDTO
中返回UserType的树,否则你应该将其保留为一个简单的"平面"DTO。