Использование IEqualityComparer с предложением LINQ to Entities Except - PullRequest
5 голосов
/ 20 января 2010

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

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

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 to Entities не распознает метод 'System.Linq.IQueryable 1[UnitedOne.Data.Sql.Product] Except[Product](System.Linq.IQueryable 1 [UnitedOne.Data.Sql.Product], System.Collections.Generic.IEnumerable 1[UnitedOne.Data.Sql.Product], System.Collections.Generic.IEqualityComparer 1 [UnitedOne.Data.Sql.Product])', и этот метод не может быть преобразован в выражение хранилища.

Ответы [ 3 ]

7 голосов
/ 20 января 2010

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

Под прикрытием кодируется знание того, как работают операторы и общие функции и как они связаны с TSQL. Проблема в том, что разработчики L2E понятия не имеют, как именно вы реализуете IEqualityComparer. Поэтому они не могут понять, что когда вы говорите «Класс A == Класс B», вы имеете в виду (например) «Где Person.FirstName == FirstName AND Person.LastName == 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

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

4 голосов
/ 20 января 2010

Вы пытаетесь преобразовать вызов 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();

    ...
}
2 голосов
/ 20 января 2010

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

...