C# Linq Группировка по объекту - PullRequest
1 голос
/ 12 апреля 2020

У меня есть проблема использования group by в операторе LINQ to SQL.

У меня есть треска

var combinedItems = (from article in articles
                     join author in authors
                     on article.AuthorId equals author.Id into tempAuthors
                     from tempAuthor in tempAuthors.DefaultIfEmpty()
                     select new { article , author = tempAuthor});

var groups1 = (from combinedItem in combinedItems
               group combinedItem by combinedItem.article into g
               select g.Key).ToList();

var groups2 = (from combinedItem in combinedItems
               group combinedItem by combinedItem.article.Id into g
               select g.Key).ToList();

Я пытался сгруппировать двумя разными способами. Первый способ - группировка по объекту, а второй - группировка по полю в одном из объектов.

Когда я запускаю groups1, я получаю сообщение об ошибке, требующее оценки на стороне клиента, в то время как когда я использую groups2, все работает хорошо. Могу я спросить, что может быть не так? Если я хочу группировать по объекту, есть ли способ сделать это?

Ответы [ 2 ]

1 голос
/ 12 апреля 2020

В случае, если вы хотите сгруппировать по объекту, так как вы не переопределили Equals и GetHashCode() в своем классе Article или внедрили IEqualityComparer<Article>, вы просто получаете сравнение по умолчанию , который проверяет, равны ли ссылки. Итак, вам нужно что-то вроде этого:

class GroupItemComparer : IEqualityComparer<Article>
{

    public bool Equals(Article x, Article y)
    {
        return x.Id == y.Id &&
            x.Name == y.Name;
    }

    public int GetHashCode(Article obj)
    {
        return obj.Id.GetHashCode() ^
            obj.Name.GetHashCode();
    }
}

А затем вам нужно изменить свой запрос на лямбда-выражение:

var groups1 = combinedItems.GroupBy(c => c.article , new GroupItemComparer())
                           .Select(c => c.Key).ToList();

На случай, если у вас возникло исключение в отношении перевода вашего метода в SQL, вы можете использовать методы AsEnumerable или ToList перед вашим методом GroupBy, с этими методами после загрузки данных любая дальнейшая операция выполняется с использованием Linq to Objects над данными, уже находящимися в памяти.

0 голосов
/ 13 апреля 2020

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

Весь смысл запроса в том, чтобы перевести ваш запрос Linq в SQL. Поскольку равенство ссылок на объекты на клиенте не может быть легко переведено на SQL, переводчик не поддерживает его и выдает ошибку.

Когда вы предоставляете одно или несколько свойств для группировки провайдер может преобразовать это значение в SQL (например, GROUP BY article.Id), и, таким образом, второй метод работает без ошибок.

...