Как получить доступ к хранилищу из доменного уровня - PullRequest
0 голосов
/ 19 мая 2011

Я думаю, что у меня может быть некоторая путаница по поводу разделения домена / уровня обслуживания.

В моем приложении код домена должен генерировать общесистемный уникальный идентификатор с деловым смыслом. Это означает, что он должен получить доступ к хранилищу с эксклюзивным доступом. Я мог бы сделать это непосредственно в коде домена, но я думаю, что это неправильно по двум причинам:

  • Код домена не должен иметь доступ к хранилищу (я думаю ...)
  • Получение эксклюзивной блокировки хранилища означает, что я буду блокировать параллельные операции над другими объектами домена, которым также необходим этот доступ, поскольку блокировка будет снята только после фиксации всего сеанса. Использовать оптимистичный параллелизм здесь расточительно: хотя генерация идентификаторов быстрая, бизнес-операции относительно длинные, что означает высокую вероятность двух одновременных бизнес-операций.

В качестве примера рассмотрим следующее:

class UnitOfWork
{
    public OrderRepository TheOrderRepository { get; private set; }
    public void Commit() { /* ... */ }
}

class UnitOfWorkFactory
{
     UnitOfWork CreateNewUnitOfWork() 
     {
         var sess = CreateNewSession();
         var trans = CreateNewTransaction(session);
         return new UnitOfWork 
             { 
                 TheOrderRepository = new OrderRepository(sess, trans);
             }
     }
}

class OrderService // application service layer
{
    public void ProcessOrder(ID id, Details details)
    {
        using (uow = UnitOfWorkFactory.CreateNewUnitOfWork())
        {
            Order order = TheOrderRepository.Load(id);
            order.Process(details);
            uow.TheOrderRepository.Update(order);
            uow.Commit();
        }
    }
}

class Order // domain layer
{
    public void Process(Details details)
    {
        // need to get a unique, business-related identifier here.
        // Where do I get it from?
    }
}

Есть два варианта:

// Option 1 - get BusinessIdRepository from Service layer

class Order // domain layer
{
    public void Process(Details details)
    {
        // bad, because other Orders will block in Process() until my Process()
        // is done.
        // also, I access the storage in my domain layer, which is a no-no (?)
        var id = m_businessIdRepository.GetUniqueId(details);
    }
}

И

// Option 2 - introduce a service. For this example, suppose the business ID is 
//            just an increasing counter

class BusinessIdBrokerService
{
    int GetBusinessId(Details details) 
    {
        int latestId;
        using (uow = UnitOfWorkFactory.CreateNewUnitOfWork())
        {
            latestId = TheIdRepository.GetLatest();  // takes lock
            latestId ++;
            TheIdRepository.SetLatestId(latestId);
            uow.Commit();  // lock is released
        }

        return latestId;
    }
}

class Order // domain layer
{
    public void Process(Details details)
    {
        // domain layer accessing the service layer. Is this bad?
        var id = m_businessIdBroker.GetBusinessId(details);
    }
}

Теперь, опция (1) имеет очевидные недостатки, но опция (2) имеет уровень домена, обращающийся к уровню обслуживания. На всех диаграммах, которые я видел, это большое нет-нет.

Следуя терминологии Джимми Богарда (http://lostechies.com/jimmybogard/2008/08/21/services-in-domain-driven-design/), похоже, я хочу здесь Службу домена (в отличие от Службы приложений), но эта Служба домена получит доступ к хранилищу (не только через хранилище: она создаст независимый сеанс) + транзакция.)

Следует отметить, что опция (2) имеет тот недостаток, что генерация идентификатора не может быть отменена в случае возникновения проблемы в Order.Process, поскольку она уже зафиксирована. У меня нет проблем с этим в моем сценарии. Я в порядке с тратить идентификаторы.

Если это имеет значение, я использую NHibernate в качестве ORM.

Какой подход вы бы порекомендовали?

1 Ответ

1 голос
/ 19 мая 2011

Чтобы удалить зависимость от Order для IdBroker, вы можете внедрить IdBrokerService, введенный в OrderService, и передать новый Id в метод Order.Process в качестве параметра.

Если вы согласны тратить идентификаторы, то независимая служба, которая генерирует новый идентификатор, вероятно, является лучшим решением в вашем случае. Затем вы добавляете этот сервис в качестве зависимости к другим сервисам, которые получают идентификаторы и передают их объектам домена. Таким образом, ваши доменные объекты остаются в стороне от любого внешнего взаимодействия.

...