Как заказать дочерние коллекции сущностей в EF - PullRequest
28 голосов
/ 09 декабря 2011

У меня следующий запрос:

public IEnumerable<Team> GetAllTeamsWithMembers(int ownerUserId)
        {
            return _ctx.Teams
                 .Include(x => x.TeamMembers)
                 .Where(x => x.UserId == ownerUserId)
                 .OrderBy(x => x.Name).ToList();

        }

Как мне упорядочить команды по их названию, а затем отсортировать всех дочерних членов каждой команды по их названию?

Кажется, что для этого мне нужно создать новый класс DTO и использовать select. Я хотел бы использовать уже созданные сущности EF, в этом случае у Team есть свойство навигации для участников. Я возвращаю IEnumerable<Team> из своего уровня хранилища.

Похоже, что в EF нет аккуратного способа упорядочить дочерние коллекции. Кто-нибудь может помочь?

Ответы [ 3 ]

24 голосов
/ 09 декабря 2011

Вы можете загрузить данные и отсортировать их в памяти после загрузки.

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

Или вы можете использовать проекции и использовать отслеживание изменений EF для сортировки вашей коллекции. Вот пример фильтрации Включить, но то же самое работает для Упорядочения.

2 голосов
/ 09 декабря 2011

Вы можете свалить свои команды и членов их команд в анонимный тип (вероятно, не тот, который вы хотите), например:

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()
}

Затем вы можете просмотреть их:

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

Обновление: Для записи, я считаю, что не следует использовать это решение, а сортировать каждую коллекцию в цикле или во время рендеринга / связывания.

Я удалил 2-е решение, посколькубыло отмечено, что EF не может выделяться в сущности.

0 голосов
/ 23 марта 2019

К сожалению, энергичная загрузка (Include) не поддерживает фильтрацию или сортировку загруженных дочерних коллекций.

Но, как указано в принятом ответе, вы можете отсортировать каждую коллекцию после того, как она будет загружена. Я написал метод расширения, который легко сортирует коллекцию по дочернему свойству вместо , поэтому переназначение не требуется:

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

Тогда сортировка дочерних коллекций может быть кратко записана как:

foreach (var team in teams)
    team.TeamMembers.SortOn(_ => _.Name);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...