Java 如何在JPQL中引用仅为联接映射的列?
假设我有以下两张表:Java 如何在JPQL中引用仅为联接映射的列?,java,jpa,jpql,Java,Jpa,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值 如果这是
@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);
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);
@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();
}
但是,您无法将其转换为JPQL,因为bar_id列未映射到实体的属性
由于bar_id没有直接映射到Foo实体上,如何在JPQL中实现这种查询?您无法直接访问bar_id。您需要在Foo和bar之间进行额外的连接,以使用来自bar实体的id信息 因此,您的JPQL查询如下所示:
UPDATE Bar SET flag = true WHERE id IN (SELECT bar_id from FOO where id = 3);
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);
@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();
}
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();
}
不会更改实际的Foo对象
我更喜欢这样做:
UPDATE Bar SET flag = true WHERE id IN (SELECT bar_id from FOO where id = 3);
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);
@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();
}
当然,您可以创建一个@Column来映射bar_id,但我不建议这样做,因为它有点违背JPA的目的。如果您想要一个工作批量更新查询,以下操作应该可以: 更新Bar b SET flag=true,其中b从FOO中选择f.Bar,其中id=3
这样做的目的是在进行子选择时使用实体。集合在哪里?这不是答案吗@sashok_bg我还没有尝试过,但我认为不会,因为在他们的示例中,我没有在实体p.country_id中映射原始外键