我想知道给定记录是否存在于数据库中。 到目前为止,我已经通过编写JPA查询并通过getSingleResult()方法运行它来实现这一点。 如果具有给定参数的记录不存在,则会抛出NoResultException。 当然,记录不是必须存在的,因此有时是正常的行为,这就是为什么我问自己,是否有必要抛出必须由catch块处理的Exception? 据我所知,异常处理的成本相当高,因此我对这种解决方案并不十分满意,而且,我什至不需要该对象,我只需要知道它在数据库中的存在即可。
有没有更好的方法来检查对象是否存在? 例如。 使用getResultList()并检查其大小?
很好的问题,但是您应该将标题更改为"如何使用JPA检查记录是否存在"或类似内容。
感谢您的发言,完成:)
更新:存储库exist(id)方法。 如果记录存在,则repo.exist(id)返回true,否则返回false
如果只想知道对象是否存在,请将SELECT COUNT发送到数据库。那将返回0或1。
异常处理的代价不是那么大(除非您在正常操作期间进行了数百万次),所以我不会打扰。
但是代码并没有真正反映出您的意图。由于getSingleResult()在内部调用getResultList(),因此更加清晰:
public boolean objExists(...) {
return getResultList(...).size() == 1;
}
如果您按对象ID查询并启用了缓存,那么如果对象已被加载,它将成为在缓存中的简单查找。
哦,您对SELECT COUNT解决方案绝对正确,由于某种原因,我忽略了它。但是答案的第二部分包含了我真正需要的信息,并对此表示非常感谢。
您是否同意,如果要获取查询的第一个结果,并且通常查询不返回任何内容,则最好执行query.setMaxResults(1)然后再执行getResultList()?这样,我们将避免处理异常。 (注意:我是在很多次的工作中运行此程序的)。
@GuilhermeA:有太多变量可以肯定地说。影响性能的因素:JDBC驱动程序,对OR映射器中DB的支持(它们如何在SQL级别上实现setMaxResults()?),表大小,查询本身等。运行一些性能测试以找出答案。
尝试避免将实体加载到会话(getSingleResult())中只是为了检查其是否存在。这里的计数更好。使用Criteria Query API,它将看起来像这样:
public boolean exists(final Class entityClass, final int id) {
final EntityManager em = getEntityManager();
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery cq = cb.createQuery(Long.class);
final Root from = cq.from(entityClass);
cq.select(cb.count(from));
cq.where(cb.equal(from.get(AbstractEntity_.id), id));
final TypedQuery tq = em.createQuery(cq);
return tq.getSingleResult() > 0;
}
您从示例中扩展哪个类?我无法在任何地方找到任何现有的exists方法。
您不会在JPA库的任何地方找到此方法。您需要在代码中的某处实现它,并使用JPA API。
那么为什么会有一个@Override注释?那就是让我感到困惑的;)
我懂了。我在接口中定义了方法,然后在类中实现了该方法。那就是它的来源。我将它从示例中删除,以避免造成进一步的混乱。
什么是AbstractEntity_?
JPA元模型。检查此答案。
只需在查询中使用count(e),就不会抛出NoResultException,并且避免加载实体对象
因此,Java代码可以如下所示:
public boolean isRecordExist() {
String query ="select count(e) from YOUR_ENTITY e where ....";
// you will always get a single result
Long count = (Long) entityManager.createQuery( query ).getSingleResult();
return ( ( count.equals( 0L ) ) ? false : true );
}
希望能帮助到某人:)
它有助于编写代码示例
如果要通过主键进行搜索,则还可以使用Entitymanger.find(entityClass, primaryKey),当该实体不存在时返回null。
如果实体存在,它将被加载到会话中,仅保留在那里。
@Radu自从我使用jpa以来已经有一段时间了,但是同样的问题将适用于使用getResultList的解决方案,对吗?
是的,考虑到getSingleResult()在内部也适用于结果列表。但是,我们这里需要的只是检查实体的存在,而没有将其加载到会话中的可能开销。计数操作将始终返回一个数字,因此我们甚至避免了NoResultException。
这是使用T类型和任意ID值的通用方法
public boolean exists(Object key) {
EntityManager entityManager = getEntityManager();
Metamodel metamodel = entityManager.getMetamodel();
EntityType< T > entity = metamodel.entity(entityClass);
SingularAttribute declaredId = entity.getDeclaredId(key.getClass());
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
javax.persistence.criteria.CriteriaQuery< T > cq = cb.createQuery(entityClass);
Root< T > from = cq.from(entityClass);
Predicate condition = cb.equal(from.get(declaredId), key);
cq.where(condition);
TypedQuery< T > q = entityManager.createQuery(cq);
return q.getResultList().size() > 0;
}