简体   繁体   English

在Linq中使用反射和Lambda表达式

[英]Use reflection and lambda expression with linq

I need to filter a collection of items by verifing the value of a flag named deletion_date 我需要verifing标志命名的值筛选项目的集合deletion_date

 public List<T> GetAll()
 {
   if (context == null) context = new ajtdevEntities();
   return context.Set<T>().Where(p => p.GetType().GetProperty("deletion_date") == null).ToList();
 }

I get an exception when I used this generic method 使用此通用方法时出现异常

LINQ to Entities does not recognize the method ' System.Reflection.PropertyInfo GetProperty ( System.String )' , and the latter can not be translated into term store. LINQ to Entities无法识别方法'System.Reflection.PropertyInfo GetProperty(System.String)',后者无法转换为术语存储。

How can I fix this method? 如何解决此方法?

Instead of reflection, you can build the filter expression manually using System.Linq.Expressions like this: 您可以使用System.Linq.Expressions这样手动构建筛选器表达式,而不是反射:

public List<T> GetAll<T>()
{
    var parameter = Expression.Parameter(typeof(T), "p");
    var predicate = Expression.Lambda<Func<T, bool>>(
        Expression.Equal(Expression.PropertyOrField(parameter, "deletion_date"), Expression.Constant(null)),
        parameter);
    if (context == null) context = new ajtdevEntities();
    return context.Set<T>().Where(predicate).ToList();
}

Note that the above will throw exception if your type does not have property/field called "deletion_date" or the type of the property does not support null . 请注意,如果您的类型没有名为“ deletion_date”的属性/字段,或者该属性的类型不支持null ,则上述内容将引发异常。 But the same can be said for your reflection based implementation (if it worked). 但是对于基于反射的实现(如果可行)也可以这样说。

An ORM will inspect the lambda and convert its parts to SQL. ORM将检查lambda并将其部分转换为SQL。 The Entity Framework team chose not to support reflection, and rightfully so. 实体框架团队选择不支持反思,这是正确的。 So it can't translate GetProperty() calls to SQL, hence the error you get. 因此它无法将GetProperty()调用转换为SQL,因此会出现错误。

It wouldn't work anyway, because GetProperty() gets a PropertyInfo instance, not the value. 无论如何,它将无法正常工作,因为GetProperty()获取的是PropertyInfo实例,而不是值。 So if it were null , that would indicate that the type of p has no property named deletion_date . 因此,如果为null ,则表明p的类型没有名为deletion_date属性。

The proper way would be to call GetValue() on the PropertyInfo (note that this will throw a NullReferenceException if there is no property named thusly): 正确的方法是在PropertyInfo上调用GetValue() (请注意,如果没有这样命名的PropertyInfo ,这将引发NullReferenceException ):

p => p.GetType().GetProperty("deletion_date").GetValue(p)

But again, reflection is not supported in Entity Framework, so you want to use interfaces: 但是同样,实体框架不支持反射,因此您要使用接口:

public interface IDeletable
{
    DateTime? deletion_date { get; set; }
}

And apply that to your class or method as a generic constraint. 并将其作为一般约束应用于您的类或方法。 Then you can use it in your lambda: 然后,您可以在lambda中使用它:

public class WhateverClass<T>
    where T : IDeletable
{
    public List<T> GetAll()
    {
        return context.Set<T>().Where(p => p.deletion_date == null).ToList();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM