簡體   English   中英

如何引用僅映射到JPQL中的連接的列?

[英]How do I refer to columns only mapped for joins in JPQL?

假設我有以下兩個表:

@Entity public class Foo {
   @Id private int id;
   @ManyToOne()
   @JoinColumn(name = "bar_id")
   private Bar bar;
}
@Entity public class Bar {
   @Id private int id;
   private Boolean flag;
}

我想編寫一個JPQL查詢,根據Foo ID的集合更改一些Bar.flag值。

如果這是普通的SQL我會寫這樣的東西:

UPDATE Bar SET flag = true WHERE id IN (SELECT bar_id from FOO where id = 3);

但是,您無法將其轉換為JPQL,因為bar_id列未映射到實體的屬性。

由於bar_id沒有直接映射到Foo實體, 我如何在JPQL中實現這種查詢?

如果您需要有效的批量更新查詢,則以下內容應該有效:

UPDATE Bar b SET flag = true WHERE b IN (SELECT f.bar from FOO f where id = 3);

當您進行子選擇時,我們的想法是與實體一起工作。

JPA的一個關鍵特性是從Java代碼中抽象出細節數據庫細節(如外鍵)。 有多種方法可以實現您所概述的查詢,以下是一對:

@Transactional
public void updateBarFlagForFoo(final int fooId, final boolean newFlagValue) {
    final Foo foo = em.find(Foo.class, fooId);
    foo.getBar().setFlag(newFlagValue);
}

或者,散裝:

@Transactional
public void updateFlags(final List<Integer> fooIds, final boolean newFlagValue) {
    final Query query = em.createQuery(
        "update Bar b set flag = :newFlagValue where b.id in " +
            "(select f.bar.id from Foo f where f.id in (:fooIds))");
    query.setParameter("newFlagValue", newFlagValue);
    query.setParameter("fooIds", fooIds);
    query.executeUpdate();
}

請注意,此類更新不會更改在同一事務中檢索的任何實體。

final Foo foo = em.find(Foo.class, 1);
updateFlags(Arrays.asList(1), true);

不會改變實際的Foo對象。

我這樣做的首選方式是這樣的:

@Transactional
public void updateFlags(final List<Integer> fooIds, final boolean newFlagValue) {
    final List<Bar> bars = findBarsForFooIds(fooIds);
    for (final Bar bar : bars) {
        bar.setFlag(newFlagValue);
    }
}

private List<Bar> findBarsForFooIds(final List<Integer> fooIds) {
    final TypedQuery<Bar> q =
            em.createQuery("select distinct b from Foo f join f.bar b where f.id in (:fooIds)",
                           Bar.class);
    q.setParameter("fooIds", fooIds);
    return q.getResultList();
}   

你當然可以創建一個映射bar_id@Column ,但我不推薦這個,因為它有點違背了JPA的目的。

您無法直接訪問bar_id 您需要在FooBar之間進行“額外”連接,以使用Bar實體的id信息。

所以,你的JPQL查詢將是這樣的:

UPDATE Bar bar SET bar.flag = true 
WHERE bar.id IN 
  (SELECT barFoo.id from FOO foo 
    JOIN foo.bar barFoo 
    WHERE foo.id = 3);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM