Я использую EntityFramework и LinqKit для построения деревьев выражений, которые переводятся в SQL. Также мы используем шаблон спецификации для организации наших запросов.
Почти во всех объектах нашей предметной области есть необходимость выполнять запрос по описанию, но в некоторых из этих классов свойство называется «Имя», в других — «Описание» и т. д.
Итак, изначально был определен интерфейс следующим образом:
public interface IDescritible
{
string Description { get; }
}
Проблема возникла, когда я попытался использовать его, явно реализованный в классе, и сделал при этом общий запрос:
public class Foo : IDescritible
{
public string Name { get; set; }
string IDescritible.Description
{
get { return this.Name; }
}
}
public class DescriptionMatch<T> : AbstractSpecification<T>
where T : IDescritible
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
return x => x.Description.Contains(Query);
}
}
При запуске EntityFramework не может преобразовать свойство get (вызов метода) в выражение SQL.
Затем я попытался определить выражение в классе следующим образом:
public interface IDescritible<T> where T: IDescritible<T>
{
Expression<Func<T, string>> DescriptionExpression { get; }
}
public class Foo : IDescritible<Foo>
{
public string Name { get; set; }
public Expression<Func<Foo, string>> DescriptionExpression
{
get { return x => x.Name; }
}
}
public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
Expression<Func<T, bool>> combinedExpression = x => x.DescriptionExpression.Invoke(x).Contains(this.Query);
return combinedExpression.Expand();
}
}
Но когда он выполняет .Expand(), возникает исключение: невозможно преобразовать объект типа «System.Linq.Expressions.PropertyExpression» в тип «System.Linq.Expressions.LambdaExpression».
Затем я узнал, что LinqKit поддерживает только расширение локальных определенных выражений (как указано в этом вопросе) и что есть некоторый неофициальный код, записываемый в решить эти проблемы (ответы на этот вопрос).
Но когда я изменил библиотеку LinqKit, чтобы попробовать одно из предложенных решений во втором вопросе, она начала выдавать: переменная «x» типа «Foo», на которую ссылается область, но она не определена.
Может быть, это было вызвано тем, что у меня еще нет экземпляра Foo? Получил только параметр универсального типа, и поэтому я не могу определить свое выражение для локальной переменной. Может быть, есть способ определить как статическое выражение, как-то «прикрепленное» к классу? Но тогда я не смогу использовать его в общем запросе, не будет интерфейса...
Есть ли способ изменить LinqKit, чтобы я мог создавать выражения, определенные для явной реализации интерфейса? Или есть другой способ сделать общий запрос по явно реализованным свойствам? Или любое другое решение или вещи, на которые нужно обратить внимание?
Для этого нет необходимости использовать ни LinqKit, ни шаблон спецификации, но EntityFramework является обязательным, важно иметь интерфейс/любой другой способ, который поддерживает «указание», какое свойство является свойством описания, и создает общее выражение для этого .
Заранее спасибо!
DescriptionExpression
без экземпляраFoo
? Это похоже на свойство класса, а не на экземпляр. Вы можете определитьDescriptionAttribute
, пометить им свое свойствоName
и построить выражение, используя только типFoo
, не имея его экземпляра. - person Konstantin Oznobihin   schedule 01.02.2014