优化NHibernate的SQL连接查询

优化NHibernate的SQL连接查询,nhibernate,join,Nhibernate,Join,以一个相当简单的域模型Orders、items和shipping为例,其中Order是根实体,shipping是根实体。我想查找给定订单的所有装运。这个问题很直截了当,但我看到了NHibernate的不良行为 模型 生成的装运对象是正确的,但查询加载的数据太多,因为我只对装运日期感兴趣。订单和行项目数据将立即丢弃,并且永远不会使用。我尝试过使用延迟加载以及我可以在网上找到的每一种获取策略,但我无法让它简单地返回基本数据 如何减少SQL查询中的噪音,使其仅加载装运数据和行项目的主键以支持延迟加载?

以一个相当简单的域模型Orders、items和shipping为例,其中Order是根实体,shipping是根实体。我想查找给定订单的所有装运。这个问题很直截了当,但我看到了NHibernate的不良行为

模型 生成的装运对象是正确的,但查询加载的数据太多,因为我只对装运日期感兴趣。订单和行项目数据将立即丢弃,并且永远不会使用。我尝试过使用延迟加载以及我可以在网上找到的每一种获取策略,但我无法让它简单地返回基本数据

如何减少SQL查询中的噪音,使其仅加载装运数据和行项目的主键以支持延迟加载?更像这样:

SELECT this_.Id            as Id5_2_,
       this_.Date          as Date5_2_,
       this_.LineItem_id   as LineItem3_5_2_,
       lineitem1_.Id       as Id4_0_,
FROM   [Shipment] this_
       inner outer join [LineItem] lineitem1_
         on this_.LineItem_id = lineitem1_.Id
WHERE  lineitem1_.Order_id = 1 /* @p0 */
自定义SQL查询更新 使用如下所示的自定义SQL查询可以获得所需的性能和正确的行为。然而,它有点违背了ORM的目的。为什么NHibernate不能生成这样一个简单的查询

Session
    .CreateSQLQuery(
            @"SELECT SH.*, LI.Id FROM Shipment SH
              INNER JOIN LineItem LI ON LI.Id = SH.LineItem_id
              WHERE LI.Order_id = ?" )
    .SetInt32( 0, order.Id )
    .List<Shipment>();

如果您只对日期感兴趣,而不是以select Shipping结束LINQ语句;,您可以选择Shipping.Date结束它;这样就不会返回完整的对象层次结构。如果你想要一些额外的细节,你可以创建一个匿名类型

var装运=来自会话.Linq中的装运,其中装运.LineItem.Order==订单
选择新建{Id=shipping.Id,Date=shipping.Date,LineItemId=shipping.LineItem.Id,OrderId=shipping.LineItem.Order.Id}

您可以向域模型订单类添加多对多关系。如果您使用的是nhibernate映射xml文件,那么可以通过向订单映射添加以下内容来实现

<bag name="Shipments" table="LineItem" lazy="true">
    <key column="id"/>
    <many-to-many class="Shipment" column="lineitem_id" />
</bag>

您应该能够在C中使用lamda表达式和新的对象初始值设定项

我已经有一段时间没有这样做了,因为我回到了旧式的2.0

我知道在linq你可以做到这一点,我不确定Nhibernate linq是否支持这一点

var shipments = from shipment in session.Linq<Shipment>()
                                where shipment.LineItem.Order == order
                                select(x => new Shipment { Date = x.Date } );

看看这个,它是用c编写的,但是在java站点上。这应该只执行一条语句,该语句将离开并选择订单等于指定订单的日期。但它会返回一个装运对象,只填充日期。

根据进一步的研究和这里的帖子。答案是你不能:

ooh这几乎奏效了。使用您的想法确实会产生一个更干净的查询,尽管它仍然有比所需更多的连接。然而,我确实需要实际的发货对象,因为实际的模型有点复杂。这是一个明显的解决方案,并且由于域的原因而不起作用。订单不负责发货。发货是发生在与订单完全不同的流程和服务中的事件。对于其他ORM中如此简单的事情,这似乎需要大量的工作。为什么我不能等到NHibernate生成一个更好、更简单的查询?我相信这是可能的,但我不完全确定如何做到这一点。以下三种方法是我开始尝试实现这一目标的地方。ISession.CreateCriteria ISession.CreateQuery ISession.CreateSqlQuery这是我能做的最好的了,我希望它能有所帮助。你能发布你的HBM文件吗?
Session
    .CreateSQLQuery(
            @"SELECT SH.*, LI.Id FROM Shipment SH
              INNER JOIN LineItem LI ON LI.Id = SH.LineItem_id
              WHERE LI.Order_id = ?" )
    .SetInt32( 0, order.Id )
    .List<Shipment>();
<bag name="Shipments" table="LineItem" lazy="true">
    <key column="id"/>
    <many-to-many class="Shipment" column="lineitem_id" />
</bag>
var shipments = from shipment in order.Shipments select shipment.Date;
var shipments = from shipment in session.Linq<Shipment>()
                                where shipment.LineItem.Order == order
                                select(x => new Shipment { Date = x.Date } );