首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >优化NHibernate的SQL join查询

优化NHibernate的SQL join查询
EN

Stack Overflow用户
提问于 2009-09-02 23:07:26
回答 4查看 2.2K关注 0票数 3

以一个相当简单的域模型Orders、items和shipment为例,其中Order是根实体,shipment是根实体。我想查找给定订单的所有发货。查询非常简单,但是我在NHibernate中看到了不受欢迎的行为。

模型

代码语言:javascript
运行
复制
public class Order
{
    public Order(){ Items = new List<LineItem>(); }
    public virtual int Id { get; private set; }
    public virtual DateTime Created { get; set; }
    public virtual IList<LineItem> Items { get; private set; }
}

public class LineItem
{
    public virtual int Id { get; private set; }
    public virtual int Quantity { get; set; }
    public virtual Order Order { get; set; }
}

public class Shipment
{
    public virtual int Id { get; private set; }
    public virtual DateTime Date { get; set; }
    public virtual LineItem LineItem { get; set; }
}

LINQ

在此查询中使用NHibernate.Linq:

代码语言:javascript
运行
复制
var shipments = from shipment in session.Linq<Shipment>()
                where shipment.LineItem.Order == order
                select shipment;

以下SQL查询的结果:

代码语言:javascript
运行
复制
SELECT this_.Id            as Id5_2_,
       this_.Date          as Date5_2_,
       this_.LineItem_id   as LineItem3_5_2_,
       lineitem1_.Id       as Id4_0_,
       lineitem1_.Quantity as Quantity4_0_,
       lineitem1_.Order_id as Order3_4_0_,
       order2_.Id          as Id3_1_,
       order2_.Created     as Created3_1_,
       order2_.IsClosed    as IsClosed3_1_
FROM   [Shipment] this_
       left outer join [LineItem] lineitem1_
         on this_.LineItem_id = lineitem1_.Id
       left outer join [Order] order2_
         on lineitem1_.Order_id = order2_.Id
WHERE  lineitem1_.Order_id = 1 /* @p0 */

产生的Shipment对象是正确的,但是查询加载了太多的数据,因为我只对shipment日期感兴趣。订单和行项目数据将立即被丢弃,并且永远不会使用。我尝试过使用延迟加载以及我能在网上找到的所有fetch策略,但我不能让它简单地返回基本数据。

如何减少SQL查询中的干扰,使其仅加载发货数据和行项目的主键,以支持延迟加载?更像这样的东西:

代码语言:javascript
运行
复制
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不能生成如此简单的查询?

代码语言:javascript
运行
复制
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>();
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-09-15 02:13:52

基于进一步的研究和这里的帖子。答案是你不能 :(

票数 0
EN

Stack Overflow用户

发布于 2009-09-02 23:25:59

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

var shipments =从session.Linq()中发货,其中shipment.LineItem.Order ==订单选择新{Id = shipment.Id,=== shipment.Date,LineItemId = shipment.LineItem.Id,OrderId = shipment.LineItem.Order.Id};

票数 1
EN

Stack Overflow用户

发布于 2009-09-02 23:45:02

您可以将多对多关系添加到域模型Order类中。如果您使用的是nhibernate映射xml文件,则可以通过在顺序映射中添加以下内容来实现。

代码语言:javascript
运行
复制
<bag name="Shipments" table="LineItem" lazy="true">
    <key column="id"/>
    <many-to-many class="Shipment" column="lineitem_id" />
</bag>

您必须向Orders类添加一个Shipments属性(应该是IList类型。否则,您可能需要非通用IList接口)。

然后,您可以查询linq中的Shipments属性,这应该会产生一个更干净的连接。

代码语言:javascript
运行
复制
var shipments = from shipment in order.Shipments select shipment.Date;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1370627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档