2011-12-15 45 views
2

我目前正在重构已使用JPA的应用程序,但JPA EnitytManager(和事务)当前的作用域为DAO层。还有一个存储库层和一个服务层。我想使服务层成为事务性的,并且在服务层上每个请求有一个EntityManger。理想情况下,我不希望我的服务或存储库层知道关于JPA的任何信息。JPA模型验证和事务处理

当前存储库和服务层使用从DAO层获得的分离实体。对模型进行更改并将实体合并回DAO层。在新结构中,实体在整个请求期间保持被管理,并且1个请求包含在1个事务中。变更在交易结束时自动提交。这看起来更像JPA的精神,并且在最常见的情况下工作得很好。

虽然有时会对模型进行更改,然后对模型进行验证。如果模型无效,则不应保存更改。在旧的结构中,这很简单:

在这个例子中,过程基本上是一个图,整个图必须验证,没有自引用,每个节点都必须可达,第一个节点有一些特殊需求,成为最终节点等等。我们首先对模型进行修改,然后验证模型。

库层的代码的时候:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    processDao.merge(process); 
    messages.addInfoMessage("Process was updated succesfully"); 
} 
return messages; 

在新的结构,我想我有三种选择,我哪一个被认为是最好的做法质疑,或是否有任何其他的替代品。

新的代码选项1:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    messages.addInfoMessage("Process was updated succesfully"); 
} else { 
    throw new InvalidProcessException(messages); 
} 
return messages; 

此代码滥用的排序为一些业务规则验证一个RuntimeException。我不认为这被认为是最佳做法,但交易是回滚的。这也与Bean Validation实例兼容,如果实体不验证,它也会引发异常。

新的代码选项2:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    messages.addInfoMessage("Process was updated succesfully"); 
} else { 
    em.getTransactionManager.rollback(); 
} 
return messages; 

此代码直接做在JPA TransactionManager回滚,并介绍了我的仓库层和JPA之间的相关性。

新的代码选项3:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    messages.addInfoMessage("Process was updated succesfully"); 
} else { 
    processDao.refresh(process); 
} 
return messages; 

这段代码看起来很不错,但它不依赖于CascadeType.REFRESH就需要刷新的过程中实体间关系正确设置。

我也可以例如到processDao.clear();processDao.rollback();但是这增加了processDao的范围到整个entityManger。我不确定这是否是一种非常干净的方法。

你对此有何看法?

回答

0

我认为你对域名持久性的了解程度越低越好。因此,在与约见到持续性作为域模型的服务,而不是把它看作模型我建议以下解决方案的一部分想法线:

  • 域必须是一致的状态,始终;
  • 所以;进入模型的变化(来自服务,你有什么样的UI)不能改变模型,而不知道将来的模型是否被验证。
  • 含义:当前模型始终保持一致。

在公式中:Future model = CurrentModel.PerformChanges()。Validated();

这怎么办?可能使用一种工作单位类型的建筑。 (http://martinfowler.com/eaaCatalog/unitOfWork.html) 每当一个domainobject被更改并被验证时,就会引发一个被更改的事件。单位工作管理器负责提取这些事件,然后确保将这些内容放入数据库中。如果更改无效,则不会引发该事件,并且该模型被标记为“无效”。因为你在隔离模式下工作,所以这不是问题。当您在共享域模型中工作时,更改必须在您的域中回滚!

这可能是解决方案中最具学术性的方法,但也许它有助于开始讨论,在这些情况下做什么......