是否允许在一个 Criteria 中多次使用相同的 DetachedCriteria?

Is it allowed to use the same DetachedCriteria within one Criteria multiple times?

我只是想知道在 Hibernate 中是否允许在一个 Criteria 中多次使用同一个 DetachedCriteria 对象。想象一下以下情况:

DetachedCriteria dCriteria = DetachedCriteria.forClass(A.class)
  .add(Restrictions.eq("id", 1))
  .setProjection(Projections.property("id"));

Criteria criteria = session.createCriteria(B.class)
  .add(
    Restrictions.or(
      Restrictions.and(
        Subqueries.exists(dCriteria),
        Restrictions.eq("id", 1)
      ),
      Restrictions.and(
        Subqueries.notExists(dCriteria),
        Restrictions.eq("id", 2)
      )
  )
  .setProjection(Projections.property("id"));

是否允许在此标准内使用 dCriteria 两次?它似乎有效,但我不确定它是否会在更复杂的情况下导致问题(也许 DetachedCriteria 在查询生成期间保存相同的状态信息?)。我已经做了一些研究,但找不到明确的答案。

不,重复使用并不(总是)安全DetachedCriteria。例如:获取列表和行数,重复使用 DetachedCriteria:

DetachedCriteria dc = DetachedCriteria.forClass(A.class);
Criteria c1 = dc.getExecutableCriteria(session);
c1.setProjection(Projections.rowCount());
long count = ((Number) c1.uniqueResult()).longValue();
System.out.println(count + " result(s) found:");

Criteria c2 = dc.getExecutableCriteria(session);
System.out.println(c2.list());

这会打印:

Hibernate: select count(*) as y0_ from A this_
4 result(s) found:
Hibernate: select count(*) as y0_ from A this_ <-- whoops
[4] <-- whoops again

不改变 DetachedCriteria 的真正简单的东西可能 是安全的,但通常将生成包装在某种工厂中并重新生成它们你需要它们的时候。

据官方说法,每次调用 getExecutableCriteria 时克隆 DetachedCriteria 永远不会发生。请参阅他们的 issues, particularly HHH-635 and HHH-1046 where Brett Meyer states: "The Criteria API is considered deprecated", and the developers guide (v4.3 §12) 其中指出:

Hibernate offers an older, legacy org.hibernate.Criteria API which should be considered deprecated. No feature development will target those APIs. Eventually, Hibernate-specific criteria features will be ported as extensions to the JPA javax.persistence.criteria.CriteriaQuery.

编辑: 在您的示例中,您在同一查询中重复使用了相同的 DetachedCriteria。因此,同样的警告适用 - 例如,如果您将 setProjection 用于其中一种用途,则第二次使用会出错。例如:

DetachedCriteria dCriteria = DetachedCriteria.forClass(A.class)
          .add(Restrictions.eq("id", 1))
          .setProjection(Projections.property("id"));

Criteria criteria = session.createCriteria(B.class)
  .add(
    Restrictions.or(
      Restrictions.and(
        Subqueries.exists(dCriteria
                .add(Restrictions.eq("text", "a1")) // <-- Note extra restriction 
                .setProjection(Projections.property("text"))), // <-- and projection
        Restrictions.eq("idx", 1)
      ),
      Restrictions.and(
        Subqueries.notExists(dCriteria),
        Restrictions.eq("idx", 2)
      )
  ))
  .setProjection(Projections.property("id"));

Object o = criteria.list();

这会产生 SQL:

select this_.idx as y0_ from B this_ 
where (
    (exists 
        (select this_.text as y0_ from A this_ where this_.id=? and this_.text=?) and this_.idx=?) 
    or (not exists 
        (select this_.text as y0_ from A this_ where this_.id=? and this_.text=?) and this_.idx=?))

我们没有要求 not existstext=? 部分,但由于 DetachedCriteria

这会导致糟糕的情况,如果您将 .add(Restrictions.eq("text" ... 应用于 dCriteria 的两种用法,它会出现SQL

中的 existsnot exists 两次