如何在列表中将具有父/子关系的实体排序在一起

时间:2013-09-25 14:55:24

标签: .net linq-to-sql

我需要能够按特定顺序订购帐户列表。他们都有一个父级/子女关系。

因此,数据看起来像这样:

AccountID    AccountName    ParentID
1            Blue           NULL
2            Red            NULL
3            Green          NULL
4            Yellow         3
5            Orange         2
6            Purple         1
7            Voilet         1
8            Gold           2

etc...

我需要填充一个下拉列表,该列表看起来像下面的(下面),由AccountID首先按字母顺序排列为NULL ParentID,然后按字母顺序排列该父节点的任何子帐户。只是添加了子帐户中的“破折号”以获得视觉效果,因此请不要担心。

Blue
- Purple
- Voilet
Green
- Yellow
Red
- Gold
- Orange

以下是我之前使用过的代码(如下所示),但在大约30个左右的帐户后,它开始给我这个错误。

SQL语句的某些部分嵌套太深。重写查询或将其分解为较小的查询。

Public Function GetAllActiveAccountsForAccountSwitcher() As IEnumerable(Of Models.AccountDropDownListModel)
    Dim isFirst As Boolean = True
    Dim list As IQueryable(Of Models.AccountDropDownListModel) = Nothing

    Dim parentAccts As IQueryable(Of Account) = From a As Account In dc.Accounts _
            And a.ParentID Is Nothing _
            Order By a.AccountName

    For Each parentAcct In parentAccts

        Dim parent = From a In dc.Accounts Where a.AccountID = parentAcct.AccountID _
            Select New Models.AccountDropDownListModel _
            With { _
                .AccountID = a.AccountID,
                .AccountName = a.AccountName
            }
        If isFirst Then
            list = parent
            isFirst = False
        Else
            list = list.Union(parent)
        End If

        Dim child = From a As Account In dc.Accounts Where a.ParentID = parentAcct.AccountID _
           Select New Models.AccountDropDownListModel _
                With { _
                    .AccountID = a.AccountID,
                    .AccountName = "- " & a.AccountName
                }
        list = list.Union(child)

    Next

    Return list
End Function

C#或VB.NET示例很好。我不可知但它需要使用linq-to-sql。存储过程不适合我的情况。

更新:这里是我对VB过敏的任何人的原始代码的c#...

public IEnumerable<Models.AccountDropDownListModel> GetAllActiveAccountsForAccountSwitcher()
{
    bool isFirst = true;
    IQueryable<Models.AccountDropDownListModel> list;

    IQueryable<Account> parentAccts = from a in dc.Accounts & a.ParentID == null orderby a.AccountName;


    foreach (void parentAcct_loopVariable in parentAccts) {
        parentAcct = parentAcct_loopVariable;
        var parent = from a in dc.Accountswhere a.AccountID == parentAcct.AccountID select new Models.AccountDropDownListModel {
            AccountID = a.AccountID,
            AccountName = a.AccountName
        };
        if (isFirst) {
            list = parent;
            isFirst = false;
        } else {
            list = list.Union(parent);
        }

        var child = from a in dc.Accountswhere a.ParentID == parentAcct.AccountID select new Models.AccountDropDownListModel {
            AccountID = a.AccountID,
            AccountName = "- " + a.AccountName
        };
        list = list.Union(child);

    }

    return list;
}

2 个答案:

答案 0 :(得分:1)

RRrrrggg我真傻。事实证明这很简单。我刚刚在模型中添加了一个“SortName”字符串,然后按照它排序。

Public Function GetAllActiveAccountsForAccountSwitcher() As IEnumerable(Of Models.AccountDropDownListModel)
    Dim parentAccts As IQueryable(Of Account) = From a As Account In dc.Accounts

    Return parentAccts.Select(Function(a) New Models.AccountDropDownListModel _
                With { _
                    .SortName = IIf(a.ParentID Is Nothing, a.AccountID, a.ParentID & "_Child"),
                    .AccountID = a.AccountID,
                    .AccountName = IIf(a.ParentID Is Nothing, a.AccountName, "- " & a.AccountName)
                }).OrderBy(Function(a) a.SortName).ThenBy(Function(a) a.AccountName)
End Function

答案 1 :(得分:0)

重写了它。我们无法保持按触发器维护的正确排序顺序,因此您必须做一些小技巧。我不确定这是否能直接用于Linq2Sql,但由于您需要所有记录,您可以将它们全部拉入List<Account>,然后在客户端对该列表进行排序。

我们将按以下顺序排序:

  1. 如果null将来自同一父母的所有项目分组在一起),则为父OR的名称或我们自己的名称
  2. 行是父级(将父级置于顶部
  3. 的事实
  4. 名称(命令子项,不影响父项
  5. 这是一个适用于我的符合您的架构的对象列表的查询:

    var result = 
        from a in Accounts
        // Get one value that is the same for both a parent & a child.
        // Since we need to sort alphabetically, we use the
        // parent name.  We only have the ID (parentId), so we need to do
        // a lookup into the list to get the parent.Name.  If the parentId
        // is null, it means we ARE the parent, so we use our own name
        let sortingGroup = Accounts.Where(x => x.Id == a.ParentId)
                                .Select(x => x.Name)
                                .FirstOrDefault() ?? a.Name
        orderby
            sortingGroup,
            a.ParentId == null descending,
            a.Name
        select new
            {
                SortingGroup = sortingGroup,
                Id = a.Id,
                Name = a.Name,
                ParentId = a.ParentId
            };
        }