【发布时间】:2021-07-05 08:50:01
【问题描述】:
我的表之间有这种关系:
Structures 表是一个多级层次结构表,其中 ParentId 与父级的 StructureId 相关。 只有根元素的 ParentId 字段为空值(正式名称为仓库)。
我想使用 nHibernate 获取位于特定仓库的任何子项(ParentId 为 null 的 Stucture)中的所有 StockabelElement。
我尝试了不同的方法。
尝试使用 CreateCriteria 这是我的代码:
var queryCriteria = unitOfWork.Session.CreateCriteria(typeof(ContainerItemModel), "containerItem");
queryCriteria.CreateAlias("containerItem.ParentContainer", "container");
queryCriteria.CreateAlias("containerItem.StockableItem", "stockableItem");
queryCriteria.CreateAlias("container.ContainerStructure", "structure");
queryCriteria.CreateAlias("structure.Parent", "parentStructure");
queryCriteria.CreateAlias("container.Company", "company");
queryCriteria.Add(Restrictions.Eq("company.ExternalCode", response.Filter.CompanyExternalCode));
我试着用这个过滤仓库:
queryCriteria.Add( Restrictions.And( Restrictions.IsNull("parentStructure.Parent") , Restrictions.Eq("parentStructure.Id", warehouseStructure.Id)));
但这不起作用(显然),因为它过滤了当前结构的第一级父级(不是仓库)。 我不知道如何在这里进行递归(如果可能)。
然后我尝试使用 HQL,这是我的代码:
var queryStr = @"
from ContainerModel as container
inner join container.ContainerItems as containerItem
inner join containerItem.StockableItem as stockableItem
inner join container.ContainerStructure as structure
left join fetch structure.Parent as parentStructure
where container.Company.ExternalCode = :companyExternalCode";
var query = unitOfWork.Session.CreateQuery(queryStr);
query.SetParameter("companyExternalCode", response.Filter.CompanyExternalCode);
但是我和以前有同样的问题......我不知道如何使用递归方式过滤我的仓库。
我可以使用从子结构获取根结构的扩展在内存 Linq 中执行此操作,但我不想在内存中执行此操作,因为在生产中我们将在 ContainerItems 表中有超过 100 万行...我认为加载所有内容不是一个好主意。 如果我使用延迟加载,我必须在之后执行数千个查询,这将是一个问题。
这是行之有效的 linq 方法,但它不是解决方案。
public static IEnumerable<T> GetParentsHierarchy<T>(this T child, Func<T, T> parentSelector)
{
var currentObject = child;
while (parentSelector(currentObject) != null)
{
yield return currentObject;
currentObject = parentSelector(currentObject);
}
//this is the ancestor parent
yield return currentObject;
}
这是我用来获取根的扩展,我可以像这样在 Linq 中使用它:
List.Where(structure => structure.GetParentsHierarchy(s => s.Parent).SingleOrDefault(s => s.StructureType == StructureType.Warehouse).Id == warehouseStructure.Id).ToList();
我希望我的目标是可以理解的。
【问题讨论】:
-
linq(可能还有 nhibernate)都生成 SQL 代码,然后将数据读入内存中的数据结构。你有什么理由相信 nhibernate 会比 linq 更有效地做到这一点?或者您可以在自定义代码中更有效地做到这一点? linq 版本有效,很容易理解。在拒绝之前,您至少应该根据生产数据对其进行基准测试。
-
感谢您的评论@Nicholas。如果我使用 linq,当我访问叶实体时,这会产生至少 2 个查询(一个用于结构,一个用于容器项)。在我对 100 个容器项的测试中(在生产中它将超过 100 万个),我看到类似 200 个查询......我不能在生产中使用这个解决方案,因为如果我的应用程序每次多做 200 万次查询,DB 管理员会杀了我天。
标签: c# orm nhibernate