Поддерживает ли LINQ to Entities IEquatable в предикате предложения where?

У меня есть простой базовый тип сущности EntityBase, который реализует IEquatable ‹EntityBase>.

Я использовал этот код вне LINQ to Entities (с EF 4.1) для фильтрации список типов, производных от EntityBase с использованием предложения предиката where, которое сравнивает экземпляры объекта, а не свойство ID, которое они наследуют от EntityBase. Итак, в основном я хочу сделать это:

UserAccount account = GetMyNewAccount();
Accounts.Where(item => item == account).SingleOrDefault();

а не это:

UserAccount account = GetMyNewAccount();
Accounts.Where(item => item.Id == account.Id).SingleOrDefault();

К сожалению, EF 4.1 и, в частности, LINQ to Entities выдают исключение:

Невозможно создать постоянное значение типа EFTest.UserAccount. В этом контексте поддерживаются только примитивные типы (такие как Int32, String и Guid).

Означает ли это, что мы не можем сделать простой предикат сравнения объектов в Entity Framework 4.1, или моя реализация IEquatable каким-то образом неверна?

P.S .: вот код IEquatable:

public class EntityBase : IEntityBase, IEquatable<EntityBase>
{
    public int Id { get; protected set; }

    #region IEquatable<EntityBase> Members

    public override bool Equals(object obj)
    {
        return Equals(obj as EntityBase);
    }

    public bool Equals(EntityBase other)
    {
        if (ReferenceEquals(other, null))
        {
            return false;
        }

        if (ReferenceEquals(this, other))
        {
            return true;
        }

        if (GetType() != other.GetType())
        {
            return false;
        }

        return Id.Equals(other.Id);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }

    public static bool operator ==(EntityBase a, EntityBase b)
    {
        if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
        {
            return true;
        }

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

        return a.Equals(b);
    }

    public static bool operator !=(EntityBase a, EntityBase b)
    {
        return !(a == b);
    }

    #endregion
}

person Mark    schedule 27.05.2011    source источник


Ответы (1)


Нет, нет. Выражения C #, которые вы передаете в Entity Framework linq-запросы, никогда не выполняются «как есть», а скорее дерево выражений оценивается и преобразуется в операторы SQL.

Глядя на вашу IEquatable реализацию, она никак не может работать - Object.ReferenceEquals() и GetType() не могут быть преобразованы в операторы SQL ..

person MattDavey    schedule 27.05.2011
comment
На самом деле это имеет смысл. Теперь мне кажется, что ORM (Genom-e), который я использовал раньше (где запрос работал), на самом деле вообще не использовал методы IEquatable, а вместо этого мог переводить выражение запроса в сравнение самих ключей - он знает о ключах, так что это вполне возможно. - person Mark; 27.05.2011
comment
Я могу либо попросить другого посетителя выполнить перевод для сравнения идентификаторов самостоятельно, либо изменить все предикаты. Не должно быть слишком сложно изменить дерево выражения перед его выполнением. - person Mark; 27.05.2011