加入笛卡儿产品

时间:2015-05-04 11:54:45

标签: java hibernate postgresql jpa

上下文

我每周都会向一些企业发送一些文件。我需要每周和每个企业恢复是否发送文件。

表格

  • ent(enterprise)
  • wek(周)
  • fil(文件:引用wek和ent)

纯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(...)

我不喜欢这个解决方案,因为它让我创建了一个显然不必要的视图。有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我有一些想法:

  1. 有2个JPA查询。首先:获取wek和企业的笛卡尔积。第二:在wek,企业和文件之间进行内部联接。使用地图(wek_id + ent_id =&gt; Tuple(Wek,Ent,File))快速识别放置文件的位置。

  2. 编写纯SQL查询并使用JPA API执行它们。

  3. (没想过这个)从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_idwek_id 一次(这可能解决重复列名称的问题)。

现在应该很容易翻译成JPA。