在没有ORM的情况下在SQL中一对多映射的方法

时间:2019-02-15 09:27:48

标签: java sql jdbc orm

假设我有一个实体。

class Building {
  List<Floor> floors;
  List<Elevator> elevators; 
}

为简单起见,楼层和电梯只有id。建筑物有id, elevator_id, floor_id

因此获取所有具有所有楼层和所有电梯的建筑物的查询将是:

select 
      id, 
      floor.id as floor_id, 
      elevator.id as elevator_id 
from building 
left join floor on (floor.building_id = building.id)
left join elevator on (elevator.building_id = building.id)

现在让我们说我有一栋2层楼的建筑和2部电梯。查询将给出如下结果集:

 id|floor_id|elevator_id
 1   f1        e1
 2   f2        e2
 1   f1        e2
 2   f2        e1 

所以有4条记录。解析它们的方式:

  1. 不是逐行,而是逐列。
  2. 分别创建每个实体
  3. 删除重复项
  4. 将所有实体合并到适当的结构中。

问题是-是否有更好的方法来解决问题?而且ORM是否在幕后做同样的事情?

因为要弄清楚它的工作原理,所以没有寻找特定的库。

1 个答案:

答案 0 :(得分:1)

运行几个查询

智能ORM应该运行2-3个查询:

  1. 获取所有建筑物及其楼层的查询
  2. 获取楼层数(如果尚未获取)的查询
  3. 获取所有电梯的查询

一旦执行了这些查询,就可以在客户端中再次合并数据。无论是在SQL中还是在ORM中,都不是一个好主意,因为要使用建议的SQL在地板和电梯之间创建笛卡尔积,因此要使用多个左联接一次性完成所有操作。想象一下,如果两个左联接在每个建筑物中都产生1000行,即使每个建筑物只有2000个子级,您也会得到1000000行重复数据。

多集旁注

请注意,SQL标准具有一个MULTISET()运算符,这在这里是最佳选择,但是很少有RD​​BMS可以实现它:

select 
  building.*,
  multiset(select * from floor where floor.building_id = building.id),
  multiset(select * from elevator where elevator.building_id = building.id)
from building 

许多数据库都支持XML和JSON,因此,如果可以将其抽象得足够好,则使用这些格式的解决方法可能有助于解决此问题。我不知道目前在Java中执行此操作的任何ORM。 jOOQ has it on the roadmap,但尚未实现。 Neither is Hibernate's version