使用AutoMapper从数据库加载实体?

时间:2016-08-28 08:09:37

标签: c# entity-framework asp.net-web-api automapper

我所阅读的大多数内容(例如from the author)表示应使用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映射到实体(即从CustomerDtoCustomer),但首先我必须使用该外键列表从中加载相应的实体数据库。 AutoMapper可以使用custom converter

执行此操作

我同意它感觉不对......但还有什么选择?将该逻辑粘贴到控制器,服务,存储库,某些管理器类中?所有这些似乎都在同一层中的其他地方推动逻辑。如果我这样做,我还必须手动执行映射!

从DDD的角度来看,DTO不应该是域的一部分。因此,AutoMapper也不属于该域,因为它知道该DTO。因此,AutoMapper与控制器,服务等处于同一层。

将DTO到实体逻辑(包括访问数据库,可能抛出异常)放入AutoMapper映射中是否有意义?

修改
@ChrisSimon下面的答案从DDD的角度解释了为什么我不应该这样做。从非DDD的角度来看,有没有令人信服的理由不使用AutoMapper从数据库加载?

1 个答案:

答案 0 :(得分:3)

首先,我将总结一下我对DDD实体的理解:

  1. 可以创建实体 - 通常使用工厂。这是他们生命周期的开始。
  2. 实体可以通过调用实体上的方法进行变异 - 修改状态。这就是他们在整个生命周期中的进展。通过确保实体拥有自己的状态,并且只能通过调用其方法来修改其状态,控制实体状态的逻辑都在实体类中,从而使业务逻辑更清晰,更易于维护系统。
  3. 使用Automapper将Dto转换为实体意味着实体放弃了其状态的所有权。如果dto处于无效状态并且您将其直接映射到实体上,则实体可能最终处于无效状态 - 您已经失去了使实体包含数据+逻辑的价值,这是DDD实体的基础。 / p>

    要提出一个关于如何处理这个问题的建议,我会问 - 你想要实现的操作是什么? 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引用的订单属于另一个客户,会发生什么情况?)
    • 询问订单(通过订单实体上的方法)是否处于有效状态以添加到客户。

    只有这样我才能将其添加到客户订单集合中。

    这样,应用程序&#39;流程&#39;和基础架构管理包含在应用程序/服务层中,但真正的业务逻辑包含在域层中 - 在您的实体中。

    如果上述要求与您的申请无关,您可能还有其他要求。如果没有,那么也许没有必要去DDD的路线 - 虽然DDD有很多东西要添加,但它的开销通常只在具有大量复杂业务逻辑的系统中值得。

    这与您提出的问题无关,但我也建议您查看客户和订单的建模。它们都是独立的Aggregates吗?如果是这样,将客户建模为包含订单集合可能会导致问题 - 当客户有一百万个订单时会发生什么?即使该集合是延迟加载的,您知道在某些时候某些东西会尝试加载它,并且会有你的表现。这里有关于聚合设计的一些很好的阅读:http://dddcommunity.org/library/vernon_2011/建议通过Id而不是引用来建模引用。在您的情况下,您可以拥有一个OrderIds集合,甚至可能是一个全新的实体来表示链接 - CustomerOrderLink,它将具有两个属性 - CustomerId和OrderId。那么你的实体都不会嵌入集合。