上下文
我每周都会向一些企业发送一些文件。我需要每周和每个企业恢复是否发送文件。
表格
纯SQL解决方案
在 ent 和 wek 之间制作笛卡尔积,然后左外连接 fil 。这有效:
select * from
(
select * from wek, ent e
) as t1
left join fil f
on f.ent_id = t1.ent_id
and f.wek_id = t1.wek_id
问题:
如何将其转换为JPA(以CriteriaBuilder方式)?
例如,如果我尝试:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ResultClass> query = cb.createQuery(ResultClass.class);
Root<Week> week = query.from(Week.class);
Root<Enterprise> query.from(Enterprise.class);
Expression<???> cartesianProduct = ??? //How?
cartesianProduct.leftJoin(???_.file);
query.where(
cb.equal(file.get(File_.wek_id), week.get(Week.week_id));
)
使用2“from”子句给我笛卡尔积,但我如何离开加入这个结果?
不满意的解决方案:
创建视图:
CREATE VIEW view_ent_wek AS
SELECT ent_id as ent_id, wek_id as wek_id, ent_id || '-' || ent_id as id
FROM ent, wek;
将其映射到实体:
@Entity
@Table(name = "view_ent_wek")
public class WeekEnterprise {
@Id
@Column(name = "id")
private String id;
@ManyToOne
@JoinColumn(name = "ent_id")
private Enterprise enterprise;
@ManyToOne
@JoinColumn(name = "wek_id")
private Week week;
[...]
然后我可以在查询中使用它:
Root<WeekEnterprise> weekEnterprise = query.from(WeekEnterprise.class);
weekEnterprise.join(...)
我不喜欢这个解决方案,因为它让我创建了一个显然不必要的视图。有什么想法吗?
答案 0 :(得分:1)
我有一些想法:
有2个JPA查询。首先:获取wek和企业的笛卡尔积。第二:在wek,企业和文件之间进行内部联接。使用地图(wek_id + ent_id =&gt; Tuple(Wek,Ent,File))快速识别放置文件的位置。
编写纯SQL查询并使用JPA API执行它们。
(没想过这个)从Wek和Ent到File创建一个后向引用(延迟加载)然后你应该能够继续你的第一个想法。
答案 1 :(得分:1)
我没有看到使用JPA进行报告式SQL查询的重点,更不用说使用Criteria Query了。
当然,JPA(及其实现)确实支持元组查询(与实体查询相反,另请参阅:Hibernate tuple criteria queries),但元组查询不是JPA擅长的。想象一下,您想要更改该报告并添加更多计算。用SQL做这件事会不会更容易?
使用JPA映射到Java对象和事务建模仍然有意义,因此,您的SQL视图解决方案已经相当不错,或者如果您不想在视图中存储SQL,请使用JPA的本机查询API: / p>
List<Object[]> list = em.createNativeQuery(sql).getResultList();
或者:
List<WeekEnterprise> list = em.createNativeQuery(sql, WeekEnterprise.class)
.getResultList();
答案 2 :(得分:0)
对JPA不太了解,但关于Postgres。我会建议这个优越的问题:
SELECT *
FROM wek CROSS JOIN ent
LEFT JOIN fil USING (ent_id, wek_id);
您不需要该子选择
结果的唯一区别(除了更短和更快):在输出中得到列ent_id
和wek_id
一次(这可能解决重复列名称的问题)。
现在应该很容易翻译成JPA。