【发布时间】:2018-04-19 21:45:31
【问题描述】:
我正在开发一个 Web 应用程序,其中包含一个派生自 .NET Core 的 IdentityUser 的 User 实体。假设有另一个名为 Comment 的实体与用户(发布评论的用户)有关系:
public class User : IdentityUser
{
public string SomeExtraField { get; set; }
}
public class Comment
{
//Owner (Creator) of the feedback
public User User { get; set; }
//body of the comment
public string Body { get; set; }
}
现在假设我有一个返回系统中所有 cmets 的 API 端点。如果我查询所有 cmets 并包含 User 关系,当对象被序列化时,User 类中的所有内容都会被序列化并发送到客户端(包括用户哈希密码等)。显然我不想要这个。所以我创建了一个CommentService 层,它从CommentRepository 中获取Comments。据我了解,服务层应该完成将原始Comment 对象映射到 Comment DTO 的工作,该 DTO 只包含应该发送给客户端的数据。我已经定义了这样的评论和用户 DTO:
public class UserOutput
{
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
public class CommentOutput
{
public UserOutput User { get; set; }
public string Body { get; set; }
}
然后在我的服务层中,我有如下内容:
//Fetch all comments
var list = await _repository.ListAsync();
//Map comments to DTO
var result = list.Select(x => new CommentOutput
{
Body = x.Body,
User = new UserOutput
{
Id = x.User.Id,
SomeExtraField = x.User.SomeExtraField,
}
});
这一切似乎都很好。但是我可以预见一个问题。假设我有一个包含评论、帖子、喜欢、私人消息等的大型系统。我可以用上面类似的方式将它们全部映射。然后有一天我决定向 UserOutput DTO 添加另一个字段。现在我必须通过可能像上面的示例那样的数百个映射代码来正确映射新字段,更糟糕的是编译器不会告诉我我是否遗漏了任何东西。我想在某处有一个函数,将User 映射到UserOutput,但我不知道它应该去哪里。
我已经看到一些建议将构造函数放入执行映射的 DTO:
public class UserOutput
{
public UserOutput(User user)
{
Id = user.Id;
SomeExtraField = user.SomeExtraField
}
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
但我看到有人反对这一点,因为它将 DTO 与实体紧密耦合在一起。我也看到了使用 Auto Mapper 的建议,但似乎也有同等数量的人反对它。
我应该在哪里放置可以执行这些 DTO->entity 和 entity->DTO 映射的代码,这样我就不会到处重复自己了?
【问题讨论】:
-
AutoMapper 的缺点是什么? IMO 你用 ToXXX() 方法或者那个写它。
-
如果您可以将 User 实例分配给像 usrOut = _usr 这样的 UserDTO 实例,这将“隐式”将 usr 转换为 usr i>usrOut? Implicit keyword
-
@Steve 我仍然需要在需要引用用户实体的 UserDTO 中定义隐式运算符。这最终会导致与在 DTO 中定义一个接受用户的构造函数相同的耦合,不是吗?
-
我相信 Automapper 至少可以通过
Mapper.AssertConfigurationIsValid();调用告诉您是否有任何字段未映射。 -
@Brad 您可以将隐式方法以及带有 User 参数的构造函数包装在 #if pragma 中,并将用户对象的存在完全移除到不存在的应用程序中不需要知道它的存在。当然,如果您将两个对象模型保存在两个不同的程序集中,并将 DTO 程序集部署到外部应用程序,同时将完整的模型仅用于内部服务,那会更好。
标签: c# .net asp.net-core dto