【问题标题】:How to filter entities with composite PK by a list of said PK using HQL?如何通过使用 HQL 的所述 PK 列表过滤具有复合 PK 的实体?
【发布时间】:2016-12-30 18:57:49
【问题描述】:

考虑:

@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 不是单个值。我只是想列出我拥有 pks 的所有实体。

可以打破列表并执行以下操作:

-- 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 ((?,?), (?,?), (?, ?))

【问题讨论】:

  • 您是否尝试过在命名参数周围不使用括号,正如我在回答中所建议的那样?
  • 您使用的是哪种 RDBMS(例如 MySQL、Oracle 等)?
  • @SteveChambers 我正在使用 Oracle(检查我的编辑)。另外,不幸的是,我无法控制数据库。
  • 对于它的价值,我使用的是 Oracle,我希望生成的 SQL 类似于.... 那么生成的 SQL 是什么样的? 当然,这是行不通的,因为 pk 不是单个值。你怎么知道的?是否在某处明确提到不支持此功能?另外,“不工作”是什么意思?返回错误的结果?抛出错误?
  • @AlanHay 如果我尝试使用这样的查询,Hibernate 会抛出 QueryException。没有生成的 SQL。如果你再次阅读这个问题,你会发现这个 HQL 只是我正在尝试做的一个例子,而不是一个实际的实现。对于你的第二个问题:我不知道。也许那个“当然”给了你错误的印象。我已经编辑了。

标签: java hibernate jpa hql


【解决方案1】:

您可以使用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();

【讨论】:

  • 好答案。不幸的是,我几乎可以肯定我仅限于 hql(我必须仔细检查这一点,很难)。很抱歉没有在我的问题中明确说明这一点。
  • 我最终做了一个解决方法。由于这是在我的环境中实际可行的唯一答案 - 尽管不是 hql - 我接受它。谢谢。
【解决方案2】:

以下适用于 MySQL:

  1. @Entity 创建一个javax.persistence.NamedQuery

    @NamedQuery(name = "select", query = "SELECT foo FROM Foo foo WHERE foo.pk IN :pks")
    
  2. 选择途径

    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 的两个检查)

【讨论】:

    猜你喜欢
    • 2016-05-05
    • 2021-12-29
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 2010-12-23
    • 2014-04-23
    相关资源
    最近更新 更多