如何使用 HQL 通过所述 PK 列表过滤具有复合 PK 的实体?

How to filter entities with composite PK by a list of said PK using HQL?

考虑:

@Entity
public class Foo {
    @EmbeddedId
    private FooPK pk;

    public FooPK getPk() { return pk; }
    public void setPk(FooPK pk) { this.pk = pk; }
}

@Embeddable
public class FooPK {
    @Column(name="ID_A")
    private Long idA;

    @Column(name="ID_B")
    private Long idB;

    public Long getIdA() { return idA; }
    public void setIdA(Long idA) { this.idA = idA; }

    public Long getIdB() { return idB; }
    public void setIdB(Long idB) { this.idB = idB; }
}

我有一个 List<FooPK>,我想在 HQL 中用作过滤器:

-- Just an example of what I'm trying to do.
SELECT foo FROM Foo foo
WHERE foo.pk IN (:pkList)

这不起作用,因为 pk 不是单个值。我只是想列出我从中获得 pk 的所有实体。

可以打破列表并做这样的事情:

-- Ugly
SELECT foo FROM Foo foo
WHERE (
       (foo.pk.idA = :idA1 AND foo.pk.idB = :idB1)
    OR (foo.pk.idA = :idA2 AND foo.pk.idB = :idB2)
    OR (foo.pk.idA = :idA3 AND foo.pk.idB = :idB3)
    -- ...
)

但我相信您可以看到这是多么丑陋和不可扩展。

我正在使用 Java 6/JPA 1/Hibernate 3

就其价值而言,我正在使用 Oracle,我希望生成的 SQL 类似于:

-- This works fine in my database, assuming the schema contains the refered table and columns.
SELECT foo.ID_A, foo.ID_B
FROM Foo foo
WHERE (foo.ID_A, foo.ID_B) in ((?,?), (?,?), (?, ?))

您可以使用 Criteria API 来替换您的 hql

// your list of FooPks
List<FooPk> pkList = ....

//Create a criteria over an entity
Criteria  criteria = session.createCriteria(Foo.class);
// add a restriction
criteria.add(Restrictions.in("pk", pkList));
// Execute query and get result.
List<Foo> foos = criteria.list();

以下适用于 MySQL:

  1. @Entity

    创建一个javax.persistence.NamedQuery
    @NamedQuery(name = "select", query = "SELECT foo FROM Foo foo WHERE foo.pk IN :pks")
    
  2. Select 通过

    final TypedQuery<Foo> typedQuery = this.entityManager.createNamedQuery("select", Foo.class);
    final FooPK fooPk = new FooPK(...); // Create example FooPK
    typedQuery.setParameter("pks", Arrays.asList(fooPk, fooPk));
    
    return typedQuery.getResultList();
    

结果SQL:

select ... from ... where foo0_.idA=? and foo0_.idB=? or foo0_.idA=? and foo0_.idB=?

(注意每个 idAidB 的两个检查)