LINQ to Entities через свойство интерфейса

У меня возникла ситуация, когда я хотел бы использовать один класс бизнес-логики для выполнения аналогичных операций с различными классами инфраструктуры сущностей. Я определил интерфейс, который эти классы реализуют в частичном файле класса.

Однако, когда я пытаюсь написать запрос LINQ to entity к этим методам интерфейса, я получаю исключение NotSupportedException, поскольку запрос использует свойства класса не напрямую, а через интерфейс.

Я хотел бы сохранить тяжелую работу на уровне базы данных, поэтому есть ли способ добиться этого, не прибегая к LINQ для объектов?

Вот некоторый код, который демонстрирует мою проблему (он использует общий класс репозитория, созданный фабрикой).

public interface INamedEntity
{
    int ID { get; set; }
    string Name { get; set; }
}

// This is an Entity Framework class which has CustomerID and CustomerName properties.
public partial class Customer: INamedEntity
{
    int INamedEntity.ID
    {
        get { return this.CustomerID; }
        set { this.CustomerID = value; }
    }
    string INamedEntity.Name
    {
        get { return this.CustomerName; }
        set { this.CustomerName = value; }
    }
}

...

public string GetName<T>(int entityID) where T: EntityObject, INamedEntity
{
    using(var repository = RepositoryFactory.CreateRepository<T>())
    {
        return repository
            .Where(e => e.ID == entityID)
            .Select(e.Name)
            .Single();
    }
}

person gareththegeek    schedule 17.02.2012    source источник


Ответы (3)


Это не поддерживается. Ваш запрос Linq-to-entities может использовать только сопоставленные свойства ваших сущностей. Если вы используете свойства интерфейса, EF не знает, как преобразовать их в SQL, потому что он не может анализировать ваш код в реализации свойства.

Не используйте интерфейсы для сущностей — EF вообще их не поддерживает. В вашем особом случае он даже не будет работать ни с каким другим ORM, потому что вы запрашиваете свойства, которые неизвестны для сопоставления. Это потребует от вас создания собственного поставщика Linq, переводящего ваш запрос в запрос с реальными сопоставленными свойствами.

person Ladislav Mrnka    schedule 17.02.2012
comment
Но есть ли способ добиться такого шаблона. В идеале должны быть блоки бизнес-логики для каждой функциональной области, работающие над интерфейсом и отображающие все соответствующие сущности. - person gareththegeek; 17.02.2012
comment
Но это означает еще один уровень отображения поверх EF, который преобразует свойства интерфейса вашей бизнес-логики в реальные свойства EF. Этот уровень сопоставления также будет преобразовывать запросы. Я не называю этот шаблон — я называю его сверхархитектурным приложением. - person Ladislav Mrnka; 17.02.2012
comment
Возможно, чрезмерно архитектурный, но как избежать копирования и вставки одного и того же кода в несколько объектов бизнес-уровня, чтобы они могли выполнять одну и ту же логику, но используя свойства сущностей с разными именами? - person gareththegeek; 17.02.2012
comment
Это слишком абстрактный вопрос, чтобы на него можно было ответить — единственная реакция может быть: рефакторинг. Просто у вас есть модель EF, и вы хотите где-то определить L2E-запросы => которые где-то должны использовать настоящие сопоставленные свойства EF. Все ваши дополнительные имена свойств являются избыточными. - person Ladislav Mrnka; 17.02.2012
comment
Я думаю, возможно, мне не удалось достаточно подробно объяснить проблемную область. Спасибо за ответы, я пересмотрю свой вопрос. - person gareththegeek; 17.02.2012
comment
Ну, это облом, я рад, что не потратил слишком много времени на попытки. - person Jesse; 20.06.2017

Следующее исключение возникает во время выполнения запроса на основе универсального источника и с элементом интерфейса, используемым в предложении where.

NotSupportedException: сопоставление члена интерфейса [InterfaceName].[MemberName] не поддерживается.

Исключение возникает только тогда, когда запрос должен возвращать несколько элементов и когда я использовал оператор ==. Я не мог воспроизвести ошибку при выполнении запроса с параметрами First, FirstOrDefault или Single или при использовании оператора equals или другого оператора в предложении where.

Ссылка: Интерфейс не поддерживается

person Ebad Masood    schedule 17.02.2012
comment
Да, это похоже на проблему. - person gareththegeek; 17.02.2012

Вы можете использовать библиотеку динамических запросов (http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx).

        if (typeof (INamedEntity).IsAssignableFrom(typeof (T)))
        {
            q = q.Where("ID ==@0", id);
        }
person Rok Bermež    schedule 02.08.2013