Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate条件查询在生成的SQL中以错误的顺序列出表_Java_Hibernate_Hibernate 5.x - Fatal编程技术网

Java Hibernate条件查询在生成的SQL中以错误的顺序列出表

Java Hibernate条件查询在生成的SQL中以错误的顺序列出表,java,hibernate,hibernate-5.x,Java,Hibernate,Hibernate 5.x,我有一个使用多个联接的条件查询,生成的SQL无序地列出了表,因此ON子句引用了一个尚未声明的表 为了重现这个问题,我创建了一个包含三个表的小数据模型:Bill、Event和一个连接表BillEvent(我在问题的末尾列出了一个带有实体定义的可运行JUnit测试)。以下条件查询因语法错误而失败,因为event1是在引用后声明的如何重写此查询,以便以正确的顺序声明表? // Get the most recent BillEvent for a bill final Criteria criteri

我有一个使用多个联接的条件查询,生成的SQL无序地列出了表,因此ON子句引用了一个尚未声明的表

为了重现这个问题,我创建了一个包含三个表的小数据模型:Bill、Event和一个连接表BillEvent(我在问题的末尾列出了一个带有实体定义的可运行JUnit测试)。以下条件查询因语法错误而失败,因为
event1
是在引用后声明的如何重写此查询,以便以正确的顺序声明表?

// Get the most recent BillEvent for a bill
final Criteria criteria = session.createCriteria(BillEvent.class, "be1")
                    .createCriteria("event", "event1")
                    .createCriteria("be1.bill")
                    .add(Restrictions.eq("id", billId))
                    .createCriteria("billEvents", "be2")
                    .createCriteria("event", "event2", JoinType.LEFT_OUTER_JOIN,
                            Restrictions.ltProperty("event1.time", "time"))
                    .add(Restrictions.isNull("event2.id"));
错误:

Caused by: org.h2.jdbc.JdbcSQLException: Column "EVENT1X1_.TIME" not found; SQL statement:

select 
    this_.id as id1_1_4_, 
    this_.billId as billId3_1_4_, 
    this_.eventId as eventId4_1_4_, 
    this_.note as note2_1_4_, 
    hibernatej2_.id as id1_0_0_, 
    hibernatej2_.label as label2_0_0_, 
    be2x3_.id as id1_1_1_, 
    be2x3_.billId as billId3_1_1_, 
    be2x3_.eventId as eventId4_1_1_, 
    be2x3_.note as note2_1_1_, 
    event2x4_.id as id1_2_2_, 
    event2x4_.time as time2_2_2_, 
    event1x1_.id as id1_2_3_, 
    event1x1_.time as time2_2_3_ 
from 
    test.billEvent this_ 
    inner join test.bill hibernatej2_ on this_.billId=hibernatej2_.id 
    inner join test.billEvent be2x3_ on hibernatej2_.id=be2x3_.billId 
    left outer join test.event event2x4_ 
        on be2x3_.eventId=event2x4_.id 
        and ( event1x1_.time<event2x4_.time ) 
    inner join test.event event1x1_ on this_.eventId=event1x1_.id 
where 
    hibernatej2_.id=? 
    and event2x4_.id is null
生成的订单将是

from root
inner join root.a on (... and root.z.prop = root.a.prop)
inner join root.z
inner join root.z.a
inner join root.z.b

BillEvent.bill
重命名为
BillEvent.zBill
(或
事件
之后的任何字母顺序)可修复此查询中的语法错误。但是,这是不可伸缩的:如果您想从连接表的另一端进行查询,该查询将失败,因为它现在按字母顺序排列不正确。

使用条件时,hibernate实际上以深度优先搜索方式遍历实体树,根据配置中的字段定义构建联接。在您的例子中,BillEvent首先遍历bill,然后遍历bill类的子字段。因此,基本上,它在创建来自bill关联的所有联接之后,创建事件实体联接。您可以在hbm.xml中定义顺序,但正如您所提到的,它的可伸缩性不强

因此,这里至少有两个选项:

  • 更改条件以使根实体不同,然后添加投影和结果转换器以获取BillEvent实体。例如:

    final Criteria criteria = session.createCriteria(Event.class, "event1") .createCriteria("event1.billEvents", "be1") .createCriteria("be1.bill", "bill1") .createCriteria("bill1.billEvents", "be2") .createCriteria("be2.event", "event2", JoinType.LEFT_OUTER_JOIN, Restrictions.ltProperty("event1.time", "event2.time")) .add(Restrictions.eq("be1.id", billId)) .add(Restrictions.isNull("event2.id")) .setProjection(Projections.projectionList() .add(Projections.property("be1.event"), "event") .add(Projections.property("be1.note"), "note")) .setResultTransformer(Transformers.aliasToBean(BillEvent.class)); 最终标准=session.createCriteria(Event.class,“event1”) .createCriteria(“事件1.billEvents”、“be1”) .createCriteria(“be1.bill”、“bill1”) .createCriteria(“bill1.billEvents”、“be2”) .createCriteria(“be2.event”、“event2”、JoinType.LEFT\u OUTER\u JOIN、, 限制.ltProperty(“event1.time”、“event2.time”)) .add(Restrictions.eq(“be1.id”,billId)) .add(Restrictions.isNull(“event2.id”)) .setProjection(Projections.projectionList()项目) .add(Projections.property(“be1.event”),“event”) .add(Projections.property(“be1.note”),“note”)) .setResultTransformer(Transformers.aliasToBean(bilevent.class));
  • 另一个可能的选择是使用hql而不是标准api。它将允许您直接从请求控制连接顺序,因为它使用不同的sql构建机制

  • 尝试使用“createAlias”而不是“createCriteria”@richarbernal,这也不起作用。至少不是在derby:memory db上使用提供的测试用例。我想您对该特定查询的解决方案不感兴趣,而是对通用解决方案感兴趣?@flo-是的,我可以在HQL中一次性编写这个,或者使用JOOQ,但我更喜欢Criteria,因为我有很多类似的查询要转换,而且看起来不那么脆弱。@Sam Ok:-)我用Criteria解决了这个问题,但我认为这不是一个通用模式:可能有帮助:
    final Criteria Criteria=session.createCriteria(BillEvent.class,“be”).createAlias(“event”,event”).createCriteria(“bill”).add(Restrictions.eq(“id”,billId)).addOrder(Order.desc(“event.time”);
    from root
    inner join root.a on (... and root.z.prop = root.a.prop)
    inner join root.z
    inner join root.z.a
    inner join root.z.b
    
    final Criteria criteria = session.createCriteria(Event.class, "event1") .createCriteria("event1.billEvents", "be1") .createCriteria("be1.bill", "bill1") .createCriteria("bill1.billEvents", "be2") .createCriteria("be2.event", "event2", JoinType.LEFT_OUTER_JOIN, Restrictions.ltProperty("event1.time", "event2.time")) .add(Restrictions.eq("be1.id", billId)) .add(Restrictions.isNull("event2.id")) .setProjection(Projections.projectionList() .add(Projections.property("be1.event"), "event") .add(Projections.property("be1.note"), "note")) .setResultTransformer(Transformers.aliasToBean(BillEvent.class));