How to order child collections of entities in EF

后端 未结 3 1159
旧时难觅i
旧时难觅i 2020-12-05 13:17

I have the following query:

public IEnumerable GetAllTeamsWithMembers(int ownerUserId)
        {
            return _ctx.Teams
                 .         


        
相关标签:
3条回答
  • 2020-12-05 13:44

    You could load the data and sort in memory after loading it.

    IEnumerable<Team> teams = _ctx.Teams
                .Include(x => x.TeamMembers)
                .Include(x => x.TeamMembers.Select(u => u.User))
                .Where(x => x.UserId == ownerUserId)
                .OrderBy(x => x.Name).ToList();
    
    foreach (var team in teams)
    {
        team.TeamMembers = team.TeamMembers.OrderBy(m => m.Name);
        foreach (var teamMember in team.TeamMembers)
        {
            teamMember.Users = teamMember.Users.OrderBy(u => u.Name);
        }
    }
    

    Or you could use Projections and use the Change Tracking of EF to sort your collection. Here is an example of filtering an Include but the same works for Ordering.

    0 讨论(0)
  • 2020-12-05 13:51

    You could dump your teams and their team members into an anonymous type (probably not what you want), like this:

    public IEnumerable<Team> GetAllTeamsWithMembers(int ownerUserId)
    {
        return (from t in _ctx.Teams
            where t.UserId == ownerUserId
            select new {
                Team = t,
                TeamMembers = t.TeamMembers.OrderBy(m => m.Name)
            }).ToList()
    }
    

    You can then loop through them:

    foreach(Team team in GetAllTeamsWithMembers(1234))
    {
        string teamName = team.Team.Name;
        string firstTeamMemberName = team.TeamMembers.First().Name;
    }
    

    Update: For the record, my opinion is to not use this solution, but to sort each collection in a loop or during rendering/binding.

    I removed the 2nd solution, since it was pointed out that EF cannot select into entities.

    0 讨论(0)
  • 2020-12-05 13:51

    Unfortunately eager loading (Include) doesn't support any filtering or sorting of loaded child collections.

    But as stated in the accepted answer, you can sort each collection after they've been eager loaded. I wrote an extension method that handles sorting a collection by a child property easily in place so there is no need for reassignment:

    public static class Extensions
    {
        public static void SortOn<T>(this List<T> enumerable, Expression<Func<T, object>> expression)
        {
            var type = expression.Parameters[0].Type;
            var memberName = ((MemberExpression)((UnaryExpression)expression.Body).Operand).Member.Name;
    
            enumerable.Sort((x, y) =>
            {
                var first = (IComparable)type.GetProperty(memberName).GetValue(x);
                var second = (IComparable)type.GetProperty(memberName).GetValue(y);
                return first.CompareTo(second);
            });
        }
    }
    

    Then sorting the child collections could be succinctly written as:

    foreach (var team in teams)
        team.TeamMembers.SortOn(_ => _.Name);
    
    0 讨论(0)
提交回复
热议问题