Использование IEqualityComparer с предложением LINQ to Entities Except

StackOverflow https://stackoverflow.com/questions/2102886

Вопрос

У меня есть объект, который я хотел бы сравнить с подмножеством и определить, нужно ли выбирать все, кроме подмножества.

Итак, мой запрос выглядит следующим образом:

Products.Except(ProductsToRemove(), new ProductComparer())

В ProductsToRemove() метод возвращает List<Product> после этого он выполняет несколько задач.Итак, в самой простой форме это то, что описано выше.

В ProductComparer() класс выглядит примерно так:

public class ProductComparer : IEqualityComparer<Product>
{
    public bool Equals(Product a, Product b)
    {
        if (ReferenceEquals(a, b)) return true;

        if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
            return false;

        return a.Id == b.Id;
    }

    public int GetHashCode(Product product)
    {
        if (ReferenceEquals(product, null)) return 0;
        var hashProductId = product.Id.GetHashCode();
        return hashProductId;
    }
}

Однако я постоянно получаю следующее исключение:

LINQ для объектов не распознает метод 'System.Linq.IQueryable1[UnitedOne.Data.Sql.Product] Except[Product](System.Linq.IQueryable1[UnitedOne.Data.Sql.Product], Система.Коллекции.Общий.IEnumerable1[UnitedOne.Data.Sql.Product], System.Collections.Generic.IEqualityComparer1[UnitedOne.Data.Sql.Product])' метод, и этот метод не может быть переведен в выражение хранилища.

Это было полезно?

Решение

Linq to Entities на самом деле не выполняет ваш запрос, это устный перевод ваш код, преобразующий его в TSQL, затем выполняющий его на сервере.

Под прикрытием он закодирован со знанием того, как работают операторы и общие функции и как они связаны с TSQL.Проблема в том, что разработчики L2E понятия не имеют, как именно вы реализуете IEqualityComparer.Поэтому они не могут понять, что когда вы говорите Класс A == Класс B, вы имеете в виду (например) "Где Person.FirstName == Имя И персона.LastName == Фамилия".

Итак, когда интерпретатор L2E обращается к методу, который он не распознает, он выдает это исключение.

Есть два способа обойти это.Во-первых, разработайте Where(), который удовлетворяет вашим требованиям к равенству, но не зависит от какого-либо пользовательского метода.Другими словами, проверяйте на равенство свойства экземпляра, а не метод Equals, определенный в классе.

Во-вторых, вы можете запустить выполнение запроса, а затем выполнить свои сравнения в памяти.Например:

var notThisItem = new Item{Id = "HurrDurr"};
var items = Db.Items.ToArray(); // Sql query executed here
var except = items.Except(notThisItem); // performed in memory

Очевидно, что это приведет к передаче гораздо большего количества данных по проводам и более интенсивному расходованию памяти.Первый вариант, как правило, самый лучший.

Другие советы

Вы пытаетесь преобразовать Except звоните с вашим заказом IEqualityComparer в Entity SQL.

Очевидно, что ваш класс не может быть преобразован в SQL.

Вам нужно написать Products.AsEnumerable().Except(ProductsToRemove(), new ProductComparer()) чтобы заставить его выполняться на клиенте.Обратите внимание, что при этом будут загружены все продукты с сервера.


Кстати, ваш ProductComparer класс должен быть одноэлементным, вот так:

public class ProductComparer : IEqualityComparer<Product> {
    private ProductComparer() { }
    public static ProductComparer Instance = new ProductComparer();

    ...
}

В IEqualityComparer<T> может быть выполнен только локально, он не может быть преобразован в команду SQL, отсюда и ошибка

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top