我正在尝试加载我正在选择的实体的子项的子集合。我试图模仿this way这样做,基本上创建两个未来的查询,然后枚举其中一个。这应该导致对数据库的两个查询:
var idd = session.CreateQuery("from ItemDeliveryDetail idd " +
"join fetch idd.ItemDelivery " +
"left join fetch idd.SupplierInvoice " +
"where idd.Id = 21931828")
.Future<ItemDeliveryDetail>();
var spc = session.CreateQuery("from SpecialCondition spc " +
"where spc.ItemDelivery " +
"in (select idd.ItemDelivery " +
"from ItemDeliveryDetail idd " +
"where idd.Id = 21931828)")
.Future<SpecialCondition>();
var result = idd.ToList();
最后一行确实导致对数据库的两次查询。查询正是我的期望(它们相当冗长,我认为它们与问题无关,但如果你想看到它们,我会粘贴它们here)。
问题是,这两个查询的结果没有合并,即以下枚举仍然会在数据库中查询每个SpecialCondition
的{{1}}:
ItemDelivery
如何解决这个问题?
答案 0 :(得分:1)
快速获胜可能是将batch-size=50
添加到ItemDelivery
和SpecialConditions
之间的行李映射中。
但是我建议你阅读Ayende的这篇博客“Eagerly loading entity associations efficiently with NHibernate”,因为它可能会为你提供你想要的答案。
这里面临着经典的选择n + 1问题。我宁愿有1次或者2次多次访问数据库,而不是一个大的cartesian product
结果集。我相信这将是最高效的路线。
答案 1 :(得分:1)
您的第二个查询不加载ItemDelivery.SpecialConditions
个收藏集;只有一个未使用的SpecialConditions列表。
我同意Rippo的看法,使用batch-size
通常更干净,性能更高,即使它会导致一两次往返。
那就是说,你的第二个问题应该是:
var spc = session.CreateQuery("from ItemDelivery id " +
"join fetch id.SpecialCondition "
"where id in (select idd.ItemDelivery " +
"from ItemDeliveryDetail idd " +
"where idd.Id = 21931828)"
.Future<ItemDelivery>();
答案 2 :(得分:0)
您需要使用两次相同的基本查询,我认为这是您的问题。
var idd = session.CreateQuery("from ItemDeliveryDetail idd " +
"join fetch idd.ItemDelivery " +
"left join fetch idd.SupplierInvoice " +
"where idd.Id = 21931828")
.Future<ItemDeliveryDetail>();
var spc = session.CreateQuery("from ItemDeliveryDetail idd " +
"join fetch idd.ItemDelivery id " +
"join fetch id.SpecialCondition spc " +
"where idd.Id = 21931828")
.Future<ItemDeliveryDetail>();
var result = idd.ToList();
是的我意识到这可能会为您带来笛卡尔产品,但我使用这种技术取得了很好的成功。