如何使用 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:
为@Entity
创建一个javax.persistence.NamedQuery
@NamedQuery(name = "select", query = "SELECT foo FROM Foo foo WHERE foo.pk IN :pks")
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=?
(注意每个 idA
和 idB
的两个检查)
考虑:
@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:
为
创建一个@Entity
javax.persistence.NamedQuery
@NamedQuery(name = "select", query = "SELECT foo FROM Foo foo WHERE foo.pk IN :pks")
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=?
(注意每个 idA
和 idB
的两个检查)