【发布时间】:2011-05-19 06:57:48
【问题描述】:
我想我可能对域/服务层分离有些困惑。
在我的应用程序中,域代码需要生成具有业务意义的系统范围的唯一标识符。这意味着它必须以独占访问权限访问存储。我可以直接在域代码中执行此操作,但我认为这是错误的,原因有两个:
- 域代码不应访问存储(我认为...)
- 获得独占存储锁意味着我将阻止对同样需要此访问的其他域对象的并发操作,因为只有在提交整个会话时才会释放锁。在这里使用乐观并发感觉很浪费:虽然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。
你会推荐什么方法?
【问题讨论】:
标签: nhibernate domain-driven-design