我读过的大部分内容(例如来自作者 http://lostechies.com/jimmybogard/2009/09/18/the-case-for-two-way-mapping-in-automapper/) 指示应使用 AutoMapper 将实体映射到 DTO。它不应该从数据库加载任何内容。
但如果我有这个怎么办:
public class Customer {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
public class CustomerDto {
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<int> OrderIds { get; set; } // here is the problem
}
我需要地图从DTO到实体(即从CustomerDto
to Customer
),但首先我必须使用该外键列表从数据库加载相应的实体。 AutoMapper 可以通过定制转换器 https://stackoverflow.com/a/3591288/3959480.
我同意这感觉不对……但是还有什么选择呢?将该逻辑粘贴到控制器、服务、存储库、某些管理器类中?所有这些似乎都在将逻辑推向同一层的其他地方。如果我这样做,我还必须手动执行映射!
从 DDD 的角度来看,DTO 不应该是域的一部分。因此 AutoMapper 也不是域的一部分,因为它知道 DTO。所以 AutoMapper 与控制器、服务等处于同一层。
那么,将 DTO 到实体的逻辑(包括访问数据库,并可能抛出异常)放入 AutoMapper 映射中是否有意义?
EDIT
@ChrisSimon 下面的精彩回答从 DDD 的角度解释了为什么我不应该这样做。从非 DDD 的角度来看,是否有令人信服的理由不使用 AutoMapper 从数据库加载?
首先,我将总结一下我对 DDD 中实体的理解:
- 实体可以被创建——通常使用工厂。这是它们生命周期的开始。
- 可以通过调用实体上的方法来改变实体 - 修改它们的状态。这就是它们在生命周期中不断进步的方式。通过确保实体拥有自己的状态,并且只能通过调用其方法来修改其状态,控制实体状态的逻辑全部位于实体类内,从而实现业务逻辑的更清晰分离和更易于维护的系统。
使用 Automapper 从 Dto 转换为实体意味着实体放弃其状态的所有权。如果 dto 处于无效状态,而您将其直接映射到实体上,则该实体最终可能会处于无效状态 - 您已经失去了使实体包含数据+逻辑的价值,而这是 DDD 实体的基础。
为了就如何解决这个问题提出建议,我会问 - 您想要实现的操作是什么? DDD 鼓励我们不要考虑 CRUD 操作,而是考虑真实的业务流程,并在我们的实体上对它们进行建模。在本例中,您似乎将订单链接到客户实体。
在应用程序服务中,我有一个类似的方法:
void LinkOrdersToCustomer(CustomerDto dto)
{
using (var dbTxn = _txnFactory.NewTransaction())
{
var customer = _customerRepository.Get(dto.Id);
foreach (var orderId in dto.OrderIds)
{
var order = _orderRepository.Get(orderId);
customer.LinkToOrder(order);
}
dbTxn.Save();
}
}
在 LinkToOrder 方法中,我将具有执行以下操作的显式逻辑:
- 检查订单不为空
- 检查客户的状态是否允许添加订单(他们当前是否处于活动状态?他们的帐户是否已关闭?等)
- 检查订单是否确实属于该客户(如果 orderId 引用的订单属于另一个客户会发生什么?)
- 询问订单(通过订单实体上的方法)是否处于可添加到客户的有效状态。
只有这样我才会将其添加到客户订单的集合中。
这样,应用程序“流”和基础设施管理包含在应用程序/服务层中,但真正的业务逻辑包含在域层中 - 在您的实体中。
如果上述要求与您的申请不相关,您可能还有其他要求。如果没有,那么也许没有必要走 DDD 的路——虽然 DDD 有很多东西需要添加,但它的开销通常只有在具有大量复杂业务逻辑的系统中才值得。
这与您提出的问题无关,但我还建议您看一下客户和订单的建模。他们都是独立的吗骨料 http://martinfowler.com/bliki/DDD_Aggregate.html?如果是这样,将 Customer 建模为包含 Order 集合可能会导致出现问题 - 当客户拥有一百万个订单时会发生什么?即使集合是延迟加载的,您也知道在某些时候会尝试加载它,并且您的性能会受到影响。这里有一些关于聚合设计的精彩读物:http://dddcommunity.org/library/vernon_2011/ http://dddcommunity.org/library/vernon_2011/它建议通过 Id 而不是引用来建模引用。在您的情况下,您可能有一个 OrderId 集合,甚至可能有一个全新的实体来表示链接 -CustomerOrderLink
它有两个属性 - CustomerId 和 OrderId。那么您的任何实体都不会嵌入集合。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)