NHibernate中的笛卡尔积到底是什么?

NHibernate中的笛卡尔积到底是什么?,nhibernate,fluent-nhibernate,Nhibernate,Fluent Nhibernate,我经常从同事那里听到“笛卡尔产品”这个词,当一个领域模型在一个集合中有一个集合,并且急切地获取该集合时。假设我有下面的模型 public class Order{ List<Product> Products } public class Product{ List<Units> Units } 我的数据库中有125份订单,当我急切地获取产品和单位的订单时,我仍然得到125份记录 List<Order> orders = repository.Get

我经常从同事那里听到“笛卡尔产品”这个词,当一个领域模型在一个集合中有一个集合,并且急切地获取该集合时。假设我有下面的模型

public class Order{
  List<Product> Products
}
public class Product{
  List<Units> Units
}
我的数据库中有125份订单,当我急切地获取产品和单位的订单时,我仍然得到125份记录

List<Order> orders = repository.GetOrdersWithProductsAndUnits();
   Assert.That(orders.Count,Is.EqualTo(125));
List orders=repository.GetOrdersWithProductsAndUnits();
断言(orders.Count,Is.EqualTo(125));
此外,当我通过VisualStudio调试器进行检查时,在产品或单元级别的订单集合中也没有发现任何重复项

因为笛卡尔积导致了重复,所以我希望数据库中的订单数量与单位数量相同(接近1000)。我是否遗漏了一些琐碎的东西,我对笛卡尔积的理解是否有偏差?或者我正在使用的查询API会自动解决笛卡尔积问题吗

仅供参考:我对数据设置也有信心。我已经通过VisualStudio调试器进行了调试,我注意到订单包含多个产品和多个单元的产品

欢迎提供任何帮助/参考资料


感谢与其他查询类型(HQL、Criteria、QueryOver)相比,NHibernate在Linq查询中自动丢弃重复的根实体。但是,正如您在上一篇评论中所说,您仍然从数据库中获得了那么多行,因此您的查询可能会很慢。

因此,笛卡尔乘积的问题是,您得到的行比SQL中需要的多,因为它返回的order列的副本对于每个子对象都具有完全相同的数据。因此,它不是获得125次订单,而是实际获得1000次订单,并在幕后“卷起”到您的订单对象中。每次重复的列是:
order0\uu0.Id、order0\u0.CustomerName、City8\u0\u0

显然,您需要重复订单Id,因为它是FK并且存在于远程表中。但是想象一下,如果您的Order对象有更多的列,并且您在具有数百万子行的数据集上这样做


使用类似冬眠犀牛的东西会给你极大的帮助。我使用了他们的EF工具,避免了笛卡尔产品的许多问题,我不知道这些问题会发生。ORMs创建笛卡尔产品的罪魁祸首通常是急于加载/深入读取对象树。使用基于视图的模型对象可以很容易地避免这种情况,而不是试图通过在客户端代码中将对象链接在一起来构建结果集。

您确定数据是按照您所说的方式设置的吗?订单中是否有与之相关的产品?是的,我确信,我已经通过Visual Studio调试窗口进行了调试。每个订单都有许多产品,每个产品都有许多单位。好的——另一件事是NHibernate正在协调“额外”记录——您是否尝试过直接运行SQL并查看结果?而且,我不认为这会导致笛卡尔积。从技术上讲,这将是针对每个产品针对每个单元加入每个订单。如果没有交叉连接,我认为这是不可能的,但我可能错了。如果我直接运行生成的SQL查询,我会得到预期的1000条记录。没关系。我希望我的POCO对象中有重复的对象是的,你说得对。事实证明,NHibernate的LINQAPI自动在结果集上执行distinctRotentyResultTransformer。因此。。我只得到了不同的订单ID,然而,在这些订单中,我确实发现了重复的产品(与单位数量相同的产品)。
select order0_.Id as Id8_0_, 
childstock1_.Id as Id23_1_,
childstock2_.Id as Id24_2_, 
order0_.CustomerName as Customer2_8_0_,  
order0_.City as City8_0_,
childstock1_.Size as Size23_1_,
childstock2_.Box as Box24_2_,
from Orders order0_  
left outer join Products childstock1_ on order0_.Id=childstock1_.OrderId  
left outer join Units childstock2_ on childstock1_.Id=childstock2_.ProductId
List<Order> orders = repository.GetOrdersWithProductsAndUnits();
   Assert.That(orders.Count,Is.EqualTo(125));