在不加入的情况下运行 NHibernate 查询

Posted

技术标签:

【中文标题】在不加入的情况下运行 NHibernate 查询【英文标题】:Running NHibernate queries without joining 【发布时间】:2010-09-23 08:10:49 【问题描述】:

我有将虚构类 Customer 映射到 Orders 列表的 Fluent 映射。现在我想在不加载订单的情况下从数据库中获取所有客户。这可以在查询/标准/等中以某种方式指定,还是 LazyLoading 是唯一的解决方案?

虚构类:

public class Customer

    public virtual int Id  get; set; 
    public virtual string Name  get; set; 
    public virtual IList<Order> Orders  get; set; 


public class Order

    public virtual int Id  get; set; 
    // ++ 

【问题讨论】:

【参考方案1】:

无论如何,延迟加载都会自动执行此操作,您是否试图避免延迟加载?为什么?

例如:

IList<Customer> customers = _session.CreateCriteria<Customer>().List<Customer>();

只会给你所有的客户。仅当您在 Customer 实体上调用 Order 集合时,才会从数据库中获取订单,例如:

foreach(Customer customer in customers)

    IList<Order> orders = customer.Orders; // Will hit the database

因此,如果您有 10 个客户,此代码将访问数据库 11 次(1 次获取客户,10 次检索每个客户的订单)。这会给您一个 SELECT N+1 问题,但如果您对每个客户的 Orders 不感兴趣,那么就不要调用 Orders 并且不会获取它们。我不是故意粗鲁,但这似乎很明显,我误解了你的问题吗?


更新:回应 cmets。如果通过 Web 服务发送您的 POCO,您应该考虑使用报告查询,因为您的 POCO 会丢失它们对您的 NHibernate Session 对象的附件,因此延迟加载将不起作用(订单集合只会返回 NULL)。换句话说,正确调用您的 Web 服务的“事物”不会了解有关 NHibernate 或您的域模型的任何信息,因此:

public IList<CustomerView> GetAllCustomers()

    return (from c in _session.Query<Customer>()
            select new CustomerView()
            
                Id = c.Id,
                Name = c.Name
            ).ToList();


public CustomerDetail GetCustomerFromId(int id)

    return (from c in _session.Query<Customer>()
            where c.Id == id
            select new CustomerDetail()
            
                Id = c.Id,
                Name = c.Name
                FullAddress = c.FormatFullAddress(),
                Orders = c.Orders,
                // other properties (snip)
            ).SingleOrDefault();

这是使用 NHibernate 3.0 内置的 LINQ 提供程序,如果您不使用 NHibernate 3.0,并且可以使用 Projections 进行报告查询。语法让我无法理解,所以在这里试试http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection

【讨论】:

在这种情况下我也投票支持延迟加载。你有什么理由不使用它吗? 好的 - 我想我应该解释一下为什么我想要这个。我有一个客户端和一个服务器端。服务器提供 GetAllCustomers 和 GetCustomerById 等休息服务。在某些情况下,我想列出所有客户,但我不想获取客户列表的完整客户对象,因为这将是服务器上不必要的负载。因此,我只想调用 GetAllCustomers - 获取没有参考的客户 - 然后如果我想要一个完整的客户,然后调用 GetCustomerById。 延迟加载很完美,我想用它。然后,我可以在从 GetCustomerById 返回之前显式初始化 Orders,并将其留给 GetAllCustomers 未初始化。但是,使用延迟加载时网络通信存在一些问题,因此我正在尝试看看是否有其他方法可以解决这个问题。她在另一个问题中描述了沟通问题:***.com/questions/3776532/… 我不确定 Nhibernate 是否会在您的客户离开自己的应用程序域并通过网络传输时将其保持为附加实体。一旦到达另一端,Customer 将成为一个分离的 POCO,Orders 将返回 NULL(或空列表)。您可能想查看报告查询,即。只需为您的 Web 服务返回一个自定义对象。 NHibernate 将每个对象包装在可以处理惰性的东西中。当您退出会话范围时,它将无法获取对象,因此会失败。它不会简单地为空。如果是这样,那就很容易了。【参考方案2】:

您可以在 Criteria 中指定 FetchMode:

var crit = session.CreateCriteria (typeof(SomeObject));
crit.SetFetchMode ("association", FetchMode.Eager);

您还可以在映射中指定关联/集合也不应该延迟加载。默认是延迟加载集合。

【讨论】:

谢谢。知道这确实很有用!它并没有解决我的问题,因为它仍然被延迟加载机制所包裹。我想做的——如果可能的话——只是省略引用。不要懒惰加载它们.. 那么,不要映射关联? 或者,当您只想检索实体中数据的“子集”时,可以创建一个“DTO”,并使用 AliasToBean 转换器。 NHibernate 将足够聪明,只加载所需的数据。 (***.com/questions/660820/…) 是的 - 我需要在主类上映射关联,但似乎创建 DTO 可能是解决方案。谢谢。

以上是关于在不加入的情况下运行 NHibernate 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何在不选择新实例的情况下将一个查询的结果加入另一个查询的结果? [复制]

如何在不使用集合运算符的情况下在 oracle 中查找不匹配的行并加入 & 还查询特定行的不匹配列名

如何在不重新加入会话的情况下检查屏幕会话的进度?

nhibernate 强制分离查询而不是加入

Access 2007 - 在不使用交叉表查询的情况下“旋转”数据

Django ORM:在不执行 N+1 查询的情况下检索帖子和最新评论