如何从域层访问存储

时间:2011-05-19 06:57:49

标签: nhibernate domain-driven-design

我想我可能对域名/服务层分离感到困惑。

在我的应用程序中,域代码需要生成具有业务含义的系统范围的唯一标识符。这意味着它必须以独占访问权限访问存储。我可以直接在域代码中执行此操作,但我认为这有两个原因:

  • 域代码不应访问存储(我认为......)
  • 获取独占存储锁意味着我将阻止其他需要此访问权限的域对象上的并发操作,因为只有在提交整个会话时才会释放锁。在这里使用乐观并发感觉很浪费:虽然ID生成很快,但业务操作相对较长,这意味着两个并发业务操作的概率很高。

例如,请考虑以下事项:

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)有域层访问服务层。在我看到的所有图表中,这是一个很大的禁忌。

遵循Jimmy Bogard的术语(http://lostechies.com/jimmybogard/2008/08/21/services-in-domain-driven-design/),看起来我想要一个域服务(而不是应用服务) )此处,但此域服务将访问存储(不仅通过存储库:它将创建一个独立的会话+事务。)

我应该注意,选项(2)的缺点是,如果Order.Process中存在问题,则无法回滚ID生成,因为它已经被提交。在我的场景中我没有问题。我很浪费ID。

如果它有所不同,我正在使用NHibernate作为我的ORM。

你会推荐什么方法?

1 个答案:

答案 0 :(得分:1)

要从订单中删除依赖关系到IdBroker,您可以注入OrderService中注入的IdBrokerService,并将新Id作为参数传递给Order.Process方法。

如果您对浪费id很好,那么生成新id的独立服务可能是您案例中的最佳解决方案。然后,您将此服务作为依赖项添加到获取ID的其他服务,并将它们传递给域对象。这样,您的域对象就可以避免任何外部交互。