0

我有一个 linq-to-sql 数据层,其中有 2 个表。“父母”和“孩子”。Child 和 Parent 之间存在关系(因此父母有很多孩子等),父母也可以有很多父母(当孩子长大并成为父母时)。

我想向用户显示这个层次结构,但我不确定如何有效地做到这一点。

低效的方法是:

foreach(Parent in db.Parents)
{
    output(Parent.Parents)
    output(Parent.Children)
}

但是,这会为循环中的每次迭代生成两次数据库往返(eek !!),如果它是一个大家庭,这将非常昂贵。

有没有更好的办法?(上帝,我希望如此!)

4

1 回答 1

1

我建议急切地加载您希望传递给 UI 的整个集合。如果生成父 -> 父集合的方法是递归的(看起来可能是这样),那么使用 L2S 代码以递归方式选择项目。这种在 UI 中迭代最终结果集合的方式不会以低效的方式触发 SQL 命令。

示例:
我不知道这是否是最好/最短/最干净的方法,但希望你能明白。static功能因为它是一个控制台应用程序。

class Program
{
    static void Main(string[] args)
    {
        foreach (ParentDTO p in GetParents().ToList())
        {
            if (p.Parent == null)
                Console.WriteLine(String.Format("{0} ({1})",
                    p.Name, p.ID.ToString()));
            else
                Console.WriteLine(String.Format("{0} ({1}){2}",
                    p.Name, p.ID.ToString(), "\r\n\t-" + p.Parent.Name));
        }

        Console.ReadKey();
    }

    private static IQueryable<ParentDTO> GetParents()
    {
        var db = new DataClasses1DataContext();
        db.Log = new DebuggerWriter();

        return from p in db.Parents
               let parentParent = GetParentOfParent(p.ParentID)
               select new ParentDTO
               {
                   ID = p.ID,
                   Name = p.Name,
                   Parent = parentParent
               };
    }

    private static ParentDTO GetParentOfParent(int? childParentID)
    {
        if (childParentID.HasValue)
            return GetParents().Single(p => p.ID == childParentID);
        else
            return null;
    }
}

表数据:

ID ParentID Name
1 NULL Bill
2 8 Mary
3 1 Gary
4 1 Milla
5 NULL Sue
6 NULL Fred
7 NULL Marg
8 7 Hillary

输出:

Bill (1)
Mary (2)
-Hillary
Gary (3)
-Bill
Milla (4)
-Bill
Sue (5)
Fred (6)
Marg (7)
Hillary (8)
-Marg

(缩进/连字符的名称是各自的父母)

这是 L2S dc 的调试器输出Log

SELECT [t0].[ID], [t0].[ParentID], [t0].[Name]
FROM [dbo].[Parent] AS [t0]
WHERE ([t0].[ID]) = @p0
- - @p0: 输入 Int (Size = 0; Prec = 0; Scale = 0) [8]
-- 上下文: SqlProvider(Sql2005) 模型: AttributedMetaModel 构建: 3.5.30729.1

SELECT [t0].[ID], [t0].[ParentID], [t0].[Name]
FROM [dbo].[Parent] AS [t0]
WHERE ([t0].[ID]) = @p0
- - @p0: 输入 Int (Size = 0; Prec = 0; Scale = 0) [7]
-- 上下文: SqlProvider(Sql2005) 模型: AttributedMetaModel 构建: 3.5.30729.1

SELECT [t0].[ID], [t0].[ParentID], [t0].[Name]
FROM [dbo].[Parent] AS [t0]
WHERE ([t0].[ID]) = @p0
- - @p0: 输入 Int (Size = 0; Prec = 0; Scale = 0) [1]
-- 上下文: SqlProvider(Sql2005) 模型: AttributedMetaModel 构建: 3.5.30729.1

SELECT [t0].[ID], [t0].[ParentID], [t0].[Name]
FROM [dbo].[Parent] AS [t0]
WHERE ([t0].[ID]) = @p0
- - @p0: 输入 Int (Size = 0; Prec = 0; Scale = 0) [1]
-- 上下文: SqlProvider(Sql2005) 模型: AttributedMetaModel 构建: 3.5.30729.1

SELECT [t0].[ID], [t0].[ParentID], [t0].[Name]
FROM [dbo].[Parent] AS [t0]
WHERE ([t0].[ID]) = @p0
- - @p0: 输入 Int (Size = 0; Prec = 0; Scale = 0) [7]
-- 上下文: SqlProvider(Sql2005) 模型: AttributedMetaModel 构建: 3.5.30729.1

..所有这些都在.ToList();生产线上一口气开火(如预期的那样)。

我希望这很有用。

于 2009-12-12T08:47:51.297 回答