代码之家  ›  专栏  ›  技术社区  ›  Anthony

Linq中的分层数据-选项和性能

  •  12
  • Anthony  · 技术社区  · 17 年前

    我有一些分层数据-每个条目都有一个id和一个(可为空的)父条目id。

    Common Table Expressions 直接地我的选择是使用几个LINQ查询在代码中组装数据,或者在CTE表面的数据库上创建一个视图。

    当数据量变大时,您认为哪个选项(或其他选项)的性能会更好? SQL Server 2008是 HierarchyId type 在Linq到SQL中受支持?

    9 回复  |  直到 17 年前
        1
  •  16
  •   Robert Harvey    16 年前

    option 也可能证明有用:

    LINQ AsHierarchy()扩展方法
    http://www.scip.be/index.php?Page=ArticlesNET18

        2
  •  8
  •   too    16 年前

    它不仅允许单亲关系,还允许多亲关系、级别指示和不同类型的关系:

    CREATE TABLE Person (
      Id INTEGER,
      Name TEXT
    );
    
    CREATE TABLE PersonInPerson (
      PersonId INTEGER NOT NULL,
      InPersonId INTEGER NOT NULL,
      Level INTEGER,
      RelationKind VARCHAR(1)
    );
    
        3
  •  6
  •   tvanfosson    17 年前

    CREATE TABLE [dbo].[hierarchical_table](
        [id] [int] IDENTITY(1,1) NOT NULL,
        [parent_id] [int] NULL,
        [data] [varchar](255) NOT NULL,
     CONSTRAINT [PK_hierarchical_table] PRIMARY KEY CLUSTERED 
    (
        [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    CREATE VIEW [dbo].[vw_recursive_view]
    AS
    WITH hierarchy_cte(id, parent_id, data, lvl) AS
    (SELECT     id, parent_id, data, 0 AS lvl
          FROM         dbo.hierarchical_table
          WHERE     (parent_id IS NULL)
          UNION ALL
          SELECT     t1.id, t1.parent_id, t1.data, h.lvl + 1 AS lvl
          FROM         dbo.hierarchical_table AS t1 INNER JOIN
                                hierarchy_cte AS h ON t1.parent_id = h.id)
    SELECT     id, parent_id, data, lvl
    FROM         hierarchy_cte AS result
    
    
    CREATE FUNCTION [dbo].[fn_tree_for_parent] 
    (
        @parent int
    )
    RETURNS 
    @result TABLE 
    (
        id int not null,
        parent_id int,
        data varchar(255) not null,
        lvl int not null
    )
    AS
    BEGIN
        WITH hierarchy_cte(id, parent_id, data, lvl) AS
       (SELECT     id, parent_id, data, 0 AS lvl
            FROM         dbo.hierarchical_table
            WHERE     (id = @parent OR (parent_id IS NULL AND @parent IS NULL))
            UNION ALL
            SELECT     t1.id, t1.parent_id, t1.data, h.lvl + 1 AS lvl
            FROM         dbo.hierarchical_table AS t1 INNER JOIN
                hierarchy_cte AS h ON t1.parent_id = h.id)
        INSERT INTO @result
        SELECT     id, parent_id, data, lvl
        FROM         hierarchy_cte AS result
    RETURN 
    END
    
    ALTER TABLE [dbo].[hierarchical_table]  WITH CHECK ADD  CONSTRAINT [FK_hierarchical_table_hierarchical_table] FOREIGN KEY([parent_id])
    REFERENCES [dbo].[hierarchical_table] ([id])
    
    ALTER TABLE [dbo].[hierarchical_table] CHECK CONSTRAINT [FK_hierarchical_table_hierarchical_table]
    

    要使用它,您可以执行以下操作--假设某种合理的命名方案:

    using (DataContext dc = new HierarchicalDataContext())
    {
        HierarchicalTableEntity h = (from e in dc.HierarchicalTableEntities
                                     select e).First();
        var query = dc.FnTreeForParent( h.ID );
        foreach (HierarchicalTableViewEntity entity in query) {
            ...process the tree node...
        }
    }
    
        4
  •  3
  •   Jason Jackson    17 年前

    1. 根据用户输入驱动对树的每一层的检索。设想一个树视图控件填充了根节点、根的子节点和根的孙子节点。只有根和子对象被展开(子对象被折叠隐藏)。当用户展开子节点时,将显示根节点的孙子节点(以前已检索并隐藏),并启动对所有曾孙节点的检索。对N层深重复该模式。此模式对于大型树(深度或宽度)非常有效,因为它只检索所需的树部分。
    2. great article
        5
  •  3
  •   JarrettV    17 年前

    public static IEnumerable<T> ByHierarchy<T>(
     this IEnumerable<T> source, Func<T, bool> startWith, Func<T, T, bool> connectBy)
    {
      if (source == null)
       throw new ArgumentNullException("source");
    
      if (startWith == null)
       throw new ArgumentNullException("startWith");
    
      if (connectBy == null)
       throw new ArgumentNullException("connectBy");
    
      foreach (T root in source.Where(startWith))
      {
       yield return root;
       foreach (T child in source.ByHierarchy(c => connectBy(root, c), connectBy))
       {
        yield return child;
       }
     }
    }
    

    我是这样称呼它的:

    comments.ByHierarchy(comment => comment.ParentNum == parentNum, 
     (parent, child) => child.ParentNum == parent.CommentNum && includeChildren)
    

    here .

        6
  •  2
  •   Ilya Ryzhenkov    17 年前

    在MS SQL 2008中,您可以使用 HierarchyID 直接来说,在sql2005中,您可能需要手动实现它们。ParentID在大型数据集上没有那么好的性能。也检查 this article 有关该主题的更多讨论。

        7
  •  1
  •   Codewerks    17 年前

    这个方法是我从 Rob Conery's blog (查看第6部分的代码,也可以查看codeplex)我喜欢使用它。可以对其进行重构以支持多个“子”级别。

    var categories = from c in db.Categories
                     select new Category
                     {
                         CategoryID = c.CategoryID,
                         ParentCategoryID = c.ParentCategoryID,
                         SubCategories = new List<Category>(
                                          from sc in db.Categories
                                          where sc.ParentCategoryID == c.CategoryID
                                          select new Category {
                                            CategoryID = sc.CategoryID, 
                                            ParentProductID = sc.ParentProductID
                                            }
                                          )
                                 };
    
        8
  •  0
  •   Amy B    17 年前

    从客户端获取数据的问题在于,您永远无法确定需要深入到多深。此方法将对每个深度执行一次往返,并且可以在一次往返中从0执行到指定深度。

    public IQueryable<Node> GetChildrenAtDepth(int NodeID, int depth)
    {
      IQueryable<Node> query = db.Nodes.Where(n => n.NodeID == NodeID);
      for(int i = 0; i < depth; i++)
        query = query.SelectMany(n => n.Children);
           //use this if the Children association has not been defined
        //query = query.SelectMany(n => db.Nodes.Where(c => c.ParentID == n.NodeID));
      return query;
    }