【问题标题】:How to Order entities with Parent/Child relationship together in a list如何在列表中对具有父/子关系的实体进行排序
【发布时间】:2013-09-26 00:41:40
【问题描述】:

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

所以,数据看起来像这样:

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...

我需要填充一个下拉列表,如下所示(如下),该列表由具有 NULL ParentID 的 AccountID 首先按字母顺序排序,然后是该父项的任何子帐户,也按字母顺序排序。子账号上的“破折号”只是为了视觉效果而添加的,所以不用担心。

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;
}

【问题讨论】:

    标签: .net linq-to-sql


    【解决方案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
    

    【讨论】:

    • 如果它做出更好的陈述,那么你的力量就会更大。我会做同样的事情,对此进行测试,然后看看它作为“新”对象的一部分是否能更好地工作。如果您将其保留为“让”(等)的一部分,您可以直接选择整个帐户对象(select a)如果您不想要子查询,也可以在表上进行自连接.
    【解决方案2】:

    重写了。我们不能像我们应该的那样保持由触发器维护的正确排序顺序,所以你必须做一些小把戏。我不确定这是否可以直接在 Linq2Sql 中工作,但由于您需要所有记录,您可以将它们全部拉入 List&lt;Account&gt;,然后在客户端对该列表进行排序。

    我们将按以下顺序订购的东西:

    1. 如果null,则为父级或我们自己的姓名(将来自一个父级的所有项目组合在一起
    2. 行是父行这一事实(将父行放在顶部
    3. 名称(命令子级,不影响父级

    这是一个对我有用的查询,它适用于与您的架构匹配的对象列表:

    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
            };
        }
    

    【讨论】:

    • 这不是先排序所有的父母,然后再排序孩子,因为所有的 parentID == null 都会排在第一位吗?
    • 不。我们所做的就是让父级和子级都具有相同的值V。对于孩子,v = my.parent.name,对于父母,v = my.name。然后当你对它进行排序时,所有的父母和孩子都会一起出现。
    • 我最终使用了我在下面发布的答案中的代码,这是一个非常简单的 sql 语句。
    • 啊 - 我明白你现在做了什么,这和我做的事情有点像,只是方式不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多