2016-01-22 154 views
1

我正面临对Queryable数据集执行查询的问题。 原始呼叫看起来是这样的:LINQ to Entities - 未识别方法

books = books.Where(b => (GetPropertyValue(b, filter.CategoryProperties.DbName) == null ? 0 : Convert.ToInt32(GetPropertyValue(b, filter.CategoryProperties.DbName))) < Convert.ToInt32(filter.Value)); 

这让我的方法不承认错误。 这当然是由于对GetPropertyValue的调用所致。然后我读到我应该自己构建表达树。 导致下面的代码:

public IQueryable<Books> GetExpression(IQueryable<Books> books, BookCategoryMapping filter) 
    { 
     var booksExpression = Expression.Parameter(typeof(Books), "b"); 
     var methodInfo = this.GetType().GetMethod("GetPropertyValue"); 
     var value = Expression.Call(methodInfo, booksExpression, Expression.Constant(filter.CategoryProperties.DbName)); 
     var left = Expression.Constant(value); 
     var right = Expression.Constant(filter.Value); 
     var expression = Expression.Equal(left, right); 
     var whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { books.ElementType }, books.Expression, Expression.Lambda<Func<Books, bool>>(expression, new ParameterExpression[] { booksExpression })); 
     return books.Provider.CreateQuery<Books>(whereExpression); 
    } 

唯一的问题是,我得到了同样的错误。看起来下面一行只产生一个表达式而不是所述表达式的值。

var value = Expression.Call(methodInfo, booksExpression, Expression.Constant(filter.CategoryProperties.DbName)); 

任何产生正确的表达式树的帮助,将不胜感激:-)

编辑: 这里的GetPropertyValue方法:

public static object GetPropertyValue(object obj, string name) 
    { 
     try 
     { 
      return obj.GetType().GetProperty(name)?.GetValue(obj, null); 
     } 
     catch (Exception ex) 
     { 
      LogManager.Log(LogLevel.Error, null, ex); 
     } 

     return obj; 
    } 
+2

你回答了你自己的问题:你不能在LINQ到实体查询中使用C#方法,因为的调用方法不能转换为SQL。如果让编译器构建表达式,或者如果自己构建表达式,它不会改变任何内容 - 它仍然不能转换为SQL。 – Maarten

+0

我认为解决方案'自己构建表达式树“的意思就是:将方法'GetPropertyValue'的内容转换为表达式,以便**可以转换为SQL。目前,您将方法**的调用**转换为表达式树,但必须将整个方法**转换为表达式树。 – Maarten

+0

您可以将“GetPropertyValue”方法添加到问题中吗? – Maarten

回答

1

的方法,下面产生一个Expression<Func<Book, bool>>,确定是否一给定Book的属性小于给定(恒定)值。您目前在GetPropertyValue中的错误检查代码可能可以通过捕获ArgumentException来代替,当您尝试为不存在的属性创建表达式时将会抛出该代码。

请注意,我假定您正在访问的属性是真正的数字,并且您只需致电Convert.ToInt32,因为您的GetPropertyValue方法返回object

Expression<Func<Book, bool>> GenerateLessThanExpression(string propertyName, int value) 
{ 
    var parameter = Expression.Parameter(typeof (Book)); 
    var property = Expression.Property(parameter, propertyName); 
    var comparison = Expression.LessThan(property, Expression.Constant(value)); 

    return Expression.Lambda<Func<Book, bool>>(comparison, parameter); 
} 

下面是一个示例使用返回非常短的书:

var filter = GenerateLessThanExpression("Pages", 5); 
var filtered = books.Where(filter); 
+0

我将添加一条评论。在Expression.LessThan我不得不解析一个类型作为第三个参数,否则我无法得到它的工作:-) –

+0

你能澄清这一点?上面的代码用样本类进行测试,并按原样运行。你是什​​么类型的“解析”? –

+0

我解析,property.Type,当然确保我比较它的值是相同的类型 –

相关问题