Мне хочется ответить Му , но я бы хотел уточнить. В итоге: Не позволяйте вашему выбору ORM диктовать, как вы определяете свою модель домена.
Цель модели предметной области состоит в том, чтобы быть богатым объектно-ориентированным API, который моделирует домен. Чтобы следовать истинному доменно-управляемому дизайну , модель домена должна быть определена без ограничений технологией .
Другими словами, Модель предметной области стоит на первом месте , и все специфичные для технологии реализации впоследствии рассматриваются mappers , которые отображают между Доменной Моделью и рассматриваемой технологией. Это часто включает оба способа: на уровень доступа к данным, где выбор ORM может вводить ограничения, и на уровень пользовательского интерфейса, где технология пользовательского интерфейса предъявляет дополнительные требования.
Если реализация чрезвычайно далека от модели предметной области, мы говорим о антикоррупционном уровне .
В вашем случае то, что вы называете моделью анемичного домена, на самом деле является уровнем доступа к данным. Лучше всего было бы определить Репозитории , которые моделируют доступ к вашим Сущностям технологически нейтральным способом.
В качестве примера, давайте посмотрим на ваш объект заказа. Моделирование Ордена, не связанного с технологией, может привести нас к чему-то вроде этого:
public class Order
{
// constructors and properties
public decimal CalculateTotal()
{
return (from li in this.LineItems
select li.CalculateTotal()).Sum();
}
}
Обратите внимание, что это простой старый объект CLR ( POCO ) и, таким образом, он не ограничен технологией. Теперь вопрос в том, как вы получаете это из своего хранилища данных?
Это должно быть сделано через абстрактный IOrderRepository:
public interface IOrderRepository
{
Order SelectSingle(int id);
void Insert(Order order);
void Update(Order order);
void Delete(int id);
// more, specialized methods can go here if need be
}
Теперь вы можете реализовать IOrderRepository, используя ваш ORM. Однако некоторые ORM (такие как Microsoft Entity Framework) требуют, чтобы вы извлекали классы данных из определенных базовых классов, так что это совсем не подходит для доменных объектов как POCO. Для этого требуется отображение.
Важно понимать, что у вас могут быть строго типизированные классы данных, которые семантически напоминают ваши доменные сущности. Однако это чистая деталь реализации, так что не смущайтесь. Класс Order, который происходит, например, от EntityObject не является классом домена - это деталь реализации, поэтому при реализации IOrderRepository необходимо сопоставить Order Data Class с Order Класс Домана .
Это может быть утомительная работа, но вы можете использовать AutoMapper , чтобы сделать это за вас.
Вот как может выглядеть реализация метода SelectSingle:
public Order SelectSinge(int id)
{
var oe = (from o in this.objectContext.Orders
where o.Id == id
select o).First();
return this.mapper.Map<OrderEntity, Order>(oe);
}