这是here的问题的后续跟踪。
首先,我在项目中没有使用 DDD。
我有一个包含3层的WCF服务:
WCF服务需要返回DTO对象,而我无法确定将“POCO”实体转换为DTO的“Translator”类的最佳位置。
我有两种选择:
方法A
让业务逻辑方法将实体返回到服务层,服务层中有一个转换器类,用于将实体转换为DTO。
优点:
CONS:
方法B
让“Translator”类从实体对象转换为放置在“业务逻辑层”中的DTO。在这种机制中 - BL方法已经返回DTO。
优点:
CONS:
任何人都可以告诉我在哪里正确的地方执行'实体==> DTO的转换?
[更新 - 已添加示例]
业务逻辑层有一个名为 UserManager 的管理器类,它有一个这样的BL方法:
public UserTasksDto GetUserInfoWithTasks(Guid userId)
{
if (userId == Guid.Empty)
throw new ArgumentException("User ID cannot be empty");
using (IMyDBEntities entities = _contextFactory.GetContext())
{
// Get POCO Object from DbContext
User user = entities.Users.Find(userId);
if (user == null)
throw new EntityNotFoundException("User was not found in the database");
if (user.Tasks.Count() == 0)
throw new Exception("User does not have any tasks !");
// Call 'Translator' static method to translate POCO to DTO
Translator.TranslateUserToUserTasksDto(user);
}
}
如上所示 - BL方法调用'translator'方法将POCO转换为DTO。 这是在内部“实体”上下文中完成的,这样翻译人员仍然可以访问用户的“任务”子项。
以下是'翻译'方法:
class Translator
{
public static UserTasksDto TranslateUserToUserTasksDto ( User userPoco )
{
UserTasksDto dto = new UserTasksDto
{
UserId = userPoco.Id,
Username = userPoco.Username,
CreationDate = userPoco.CreationDate,
// Accessing a related entity, this is why this 'translate' method
// needs to be called inside the DbContext, otherwise it will except
// (or we load all related entities using 'Include' just for the 'Count' purpose)
Supervisor = userPoco.Supervisor.Username,
NumOfTasks = userPoco.Tasks.Count(),
FirstTaskDate = userPoco.Tasks.OrderBy(task => task.Date).Take(1),
}
return dto;
}
}
正如您在上面所看到的 - “翻译”方法从“用户”POCO对象“构建”'UserTasksDto'。 这是通过将“用户”对象及其相关实体中的某些字段映射到DTO来完成的。 如果这个方法不是里面 BL方法的ObjectContext - 我会得到一个例外,说我试图访问没有上下文的实体。
我希望我现在的问题更清楚......
答案 0 :(得分:2)
虽然有问题,
如果您需要服务层独立于BL / DAL数据实体,那么, 在我看来,你必须为独立模型设置一个新的抽象层(dll程序集)。
您的BL和/或DAL现在不会返回实体,而是返回此新程序集中的模型对象。
您的服务图层不需要引用实体的DAL,而是引用新的模型程序集。
这是与视图模型类似的模式。
现在,服务层的工作是将模型转换为DTO,如果它选择这样做。
PROS:会释放您的BL / DAL依赖
缺点:模型抽象层看起来好像是redundent
修改强>
哦,我不是故意要从业务层返回DTO。 我的意思是从业务逻辑中返回独立模型,以便它们真正独立于所有层,并且随后使用它们的任何层都可以使用它们或将它们转换为所需的任何形式。
例如,服务层可以包括DTO转换器的模型,表示层可以将它们转换为视图模型,存储库可以选择将它们转换为XML ....等等。现在每个层都有自己的Model to X转换器,BL只有单一责任,所有层都独立于DAL实体。
N.B。有些图层可能会选择直接使用它们,我相信这是你关注的问题,是的,如果他们这样做,他们会表现得好像BL返回了DTO / VM,但这不是我的意图。
希望现在能够解决问题......
<强>更新强>
请注意,您是一名开发人员,除了BL之外不会写任何图层。
您会返回DAL的实体吗?没有。
您是否有任何关于如何使用库以及将使用哪些层的概念。 NO。
您将在DAL实体之上创建一个新的抽象,并将这些抽象返回到将使用您的库的WHICHEVER层。
因此,如果开发人员X出现并使用您的库创建ACME WCF服务,我很确定X不会将您的模型对象用作他的DTO,而是X将使用您的模型作为开始创建DTO。
Developer Y出现并使用您的库创建一个ACME ASP.NET MVC 3应用程序,我很确定Y不会将您的模型对象用作他的VM(View Models),而是Y将使用您的模型创建VM一个开始。
答案 1 :(得分:0)
可能没有正确的位置,但最合乎逻辑的地方是您的业务逻辑。