【问题标题】:Filtering entities by related entity in hierarchy table按层次结构表中的相关实体过滤实体
【发布时间】: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


【解决方案1】:

我认为以这种方式做我想做的事是不可能的。 我解决了在父结构上执行 LINQ 递归查询收集所有子标识符的问题。 在我使用 Restriction.In 和结构标识符集合简单地添加了对我的条件的限制之后。

query.Add( Restrictions.In("structure.Id", childStructures.Select(s=>s.Id).ToArray()));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-14
    • 2013-01-03
    相关资源
    最近更新 更多