【发布时间】:2016-12-13 12:14:27
【问题描述】:
我正在开发一个使用 JPA(不是 JPA-2)的遗留代码库,并且在 DAO 实现类中遇到了以下方法来通过 ID 检索单个实体(这也是它的主键):
public EmailTemplate findEmailTemplateById(long id) {
LOG.debug("Entering findEmailTemplateById(id='" + id + "')");
// Construct JPQL query
String queryString = "SELECT a FROM EmailTemplate a " +
"WHERE templateId = :templateId";
Query query = entityManager.createQuery(queryString);
query.setParameter("templateId", id);
LOG.debug("Using query " + queryString);
List<EmailTemplate> resultList = query.getResultList();
LOG.debug("Exiting findEmailTemplateByName(id='" + id + "') results size " + resultList.size() + " ( returns null if 0 )");
if (resultList.isEmpty() || resultList.size() == 0) {
return null;
} else {
return resultList.get(0);
}
}
我现在需要为不同的实体编写一个类似的 DAO 类,而我通过主键查找实体的方法看起来要简单得多! :
@Override
public EmailTemplateEdit findEmailTemplateEditById(long id) {
LOG.debug("Entering findEmailTemplateEditById(id={})", id);
return entityManager.find(EmailTemplateEdit.class, id);
}
原作者不在问,所以我想知道是否有人可以就他构建 JPQL 查询而不是简单地使用EntityManager#find(Class<T> entityClass, Object primaryKey) 提出原因?
find 方法的 javadoc 说:
如果实体实例包含在持久化上下文中,它是 从那里返回。
这表明某种形式的缓存和/或延迟写入。 createQuery 和 getResultList 方法的 javadoc 没有这样说。
我不知道此应用程序中有任何会妨碍缓存的业务或技术要求,或者因过时实体或类似情况而导致的任何问题。如果可用,我将与项目团队的其他成员一起检查这些内容,但我只是想征求 SO 社区的意见,看看是否有其他原因导致构造和执行查询而不是简单地使用 find
(我见过这个:When use createQuery() and find() methods of EntityManager?。虽然它回答了这个问题:createQuery 和 find 之间的区别,但它没有在通过主键查找实体的上下文中回答它)
更新了更多信息
从查看原始 DAO 类中的其他方法来看,似乎已经有意/有意识地决定不利用 JPA 托管对象。如上所述,通过主键查找的方法使用 JPQL 查询。删除实体的方法也使用 JPQL 查询。更新实体的方法会复制传入的实体对象并使用该副本调用EntityManager#merge(因此该副本是托管对象,但从未使用或从该方法返回)
奇怪....
【问题讨论】:
-
听起来以前的开发人员不知道 JPA 的真正工作原理,因此做了一些变通方法。我自己也遇到过这种情况。
-
如果您在下面查看我关于持久性上下文的答案,我可以补充说,合并是将分离的实体添加到持久性上下文的操作。大多数人认为它的行为就像坚持,但有一个关键的细节。当您调用 merge 时,参数仍然是一个分离实体,返回值是一个托管实体(这是因为持久性上下文中的每个实体只能由一个 java 对象表示,如果分离实体已加载到上下文中,则它是已经是托管实体,因此返回,并且将是与要合并的参数不同的实例)
标签: java entity-framework hibernate jpa