言归正传,最近用到了"纵表"的设计,主表跟从表是一对多关系,从表是个简单的key:value对,另外还有个外键用来关联主表主键。
主表:主表ID,名称,XXX
从表:从表ID,主表ID,Key,Value
持久化对象的类上只需要在主表的类中加入一个Map的属性,就能把从表的键值对加载过来,假设主表是一个Group表,从表是一个Group_params表:
@ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "GROUP_PARAMS", joinColumns = @JoinColumn(name = "GROUP_ID")) @MapKeyColumn(name = "PARAM_KEY") @Column(name = "PARAM_VALUE") private MapgroupParams = new HashMap ();
在做完了这些之后,在增删改的时候都能以groupParams这个属性来拿到从表中的相关数据。
但是查询的时候遇到了一些问题,例如:根据param的Key和value查询group。
第一是要解决怎么写的问题,JPQL中使用了"Path Expressions"的方式来获取属性,也对Map这种数据结构提供了方法: KEY, VALUE, ENTRY, 也对应了Map当中的属性。
用法(以下写法有问题):
@Query(value = "select g from MyGroup g join g.groupParams p where KEY(p) = :paramKey and VALUE(p) = :paramValue ")
用了上述的注解后生成的native SQL(重点在查询条件):
where groupparam1_.param_key=? and (select groupparam1_.param_value from group_params groupparam1_ where mygroup0_.group_id=groupparam1_.group_id)=?;
可以看到查询是有问题的,Value方法直接导致生成了子查询。解决方法是把第二个查询条件的 VALUE(p) = :paramValue 直接修改为p=:paramValue.
具体的原因我只能通过查询获取一点信息,没有从源码级别看,hibernate东西还是挺多的,相关链接见:
https://stackoverflow.com/questions/29852701/is-it-possible-to-query-jpa-entities-by-elementcollections-where-the-elementcoll
https://stackoverflow.com/questions/21263725/jpas-mapkey-value-query-by-jpql-failed