我正在使用NHibernate 3.3.1和FluentNhibernate 1.3进行数据层。
我有以下实体:
数据库图表:
我需要一种方法来获取产品媒体的MediaCategory的产品。我希望NHibernate只向db发送一个查询并获取产品的所有子属性。
我希望NHibernate发送如下查询:
declare @mediaCategoryId int = 13
select *
from Product p
inner join Media m on m.ProductId=p.Id
inner join MediaCategoryMedia mcm on mcm.MediaId=m.Id
inner join MediaCategory mc on mc.Id=mcm.MediaCategoryId
left join ProductSeller ps on ps.ProductId=p.Id
left join Seller s on ps.SellerId=s.Id
where mc.Id=@mediaCategoryId
我尝试了以下选项来解决这一挑战;
会话.QueryOver< ProductEntity >()
...
我尝试了Inner.JoinQueryOver< .. >().Fetch.Eager
...但我无法获取所有子实体。
session.CreateCriteria< ProductEntity >().SetFetchMode("",FetchMode.Eager)
...
在这种情况下,延迟加载工作,我不想要lazyload。如果我从映射中禁用lazyload,NH会发送大量查询..我想要的是一个单一查询来获取所有子实体。
session.Query< ProductEntity >().FetchMany(p=>p.MediaList).ThenFetchMany(m=>m.SellerList)
...
在这种情况下,我无法创建传递mediaCategoryId过滤器的别名。相反,我使用.Where(x=>x.MediaList.Any(m=>m.CategoryList.Any(...)))
并且生成的查询也不是最佳的。
(来自会话中的p。查询&lt; ProductEntity&gt;()
来自p.MediaList中的m
来自c.m.MediaCategoryList中的c
其中c.Id == 23
select p).Fetch(x =&gt; x.MediaList);
这也不是我想要的......
var hql=@"select p from ProductEntity as p join fetch p.MediaList as m join fetch m.MediaCategoryList as mc left join fetch p.SellerList as s where mc.Id=:catId ";
这适用于hql中的“join fetch”
我需要这种情况的最佳实践,但Hql是国王。
我们可以使用session.Query<>()
或session.CreateCriteria,
或QueryOver
处理此案例吗?
答案 0 :(得分:6)
直接翻译您的查询...
Media mediaAlias = null;
MediaCategory categoryAlias = null;
return session.QueryOver<Product>()
.JoinAlias(x => x.Medias, () => mediaAlias)
.JoinAlias(() => mediaAlias.Categories, () => categoryAlias)
.Fetch(x => x.Sellers).Eager
.Where(() => categoryAlias.Id == mediaCategoryId)
.List();
默认情况下, JoinAlias
执行内连接,Fetch(...).Eager
执行左外连接。 JoinAlias
允许我们通过媒体挖掘类别,并且还急切地获取数据。
请注意,此查询中的卖家和媒体之间存在笛卡尔积。如果单个产品上有20个Medias和20个Sellers,则此查询将返回20 * 20 = 400行,这对于性能而言并不理想。您可以通过将媒体提取和卖方提取分成单独的查询来解决此问题,但是使用Future()
将它们一起批量处理到数据库,这意味着查询将返回20 + 20 = 40行。好多了。
此外,此查询不会返回与媒体关联的所有类别。如果需要,则应在Exists子查询中应用mediaCategoryId
约束。