2015-11-19 25 views
9

Hãy nói rằng tôi có hai bảng sau:Làm thế nào để tôi tham khảo các cột chỉ được ánh xạ cho các kết nối trong 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; 
} 

Và tôi muốn viết một truy vấn JPQL rằng những thay đổi một số Bar.flag giá trị dựa trên một tập hợp các Foo id.

Nếu đây là SQL đơn giản tôi muốn viết một cái gì đó như thế này:

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

Bạn không thể dịch này để JPQL Tuy nhiên, bởi vì cột bar_id không được ánh xạ đến một thuộc tính của thực thể.

bar_id không được ánh xạ trực tiếp trên Foo Thực thể, làm cách nào tôi có thể đạt được loại truy vấn này trong JPQL?

+0

bộ sưu tập ở đâu? –

+0

không phải câu trả lời này? http://stackoverflow.com/questions/3629259/how-do-i-do-a-jpql-subquery –

+0

@sashok_bg Tôi đã không thử nó, nhưng tôi không nghĩ rằng sẽ bởi vì tôi không có các khóa ngoài thô được ánh xạ trong thực thể ('p.country_id' trong ví dụ của chúng) – SCdF

Trả lời

3

Nếu bạn muốn có một truy vấn cập nhật hàng loạt làm việc, sau đây nên làm việc:

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

Ý tưởng là để làm việc với các đơn vị, khi bạn thực hiện subselect.

0

Bạn không thể truy cập trực tiếp vào số bar_id. Bạn cần thực hiện liên kết "thêm" giữa FooBar để sử dụng thông tin id từ thực thể Bar.

Vì vậy, truy vấn JPQL của bạn sẽ như thế này:

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); 
2

Một trong những tính năng chính của JPA được trừu tượng hóa đi nitty-gritty cơ sở dữ liệu chi tiết (như các phím nước ngoài) từ mã Java của bạn. Có nhiều cách để đạt được các truy vấn mà bạn đang phác thảo, đây là một vài:

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

hay, với số lượng lớn:

@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(); 
} 

Lưu ý rằng một bản cập nhật này sẽ không thay đổi bất kỳ thực thể lấy ra trong cùng một Giao dịch. Làm

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

sẽ không thay đổi đối tượng Foo thực tế.

cách ưa thích của tôi để làm điều này sẽ là một cái gì đó như thế này:

@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(); 
} 

Bạn có thể tất nhiên tạo ra một @Column rằng ánh xạ bar_id, nhưng tôi sẽ không khuyên bạn này, vì nó loại đánh bại mục đích của JPA.

Các vấn đề liên quan