Reputation: 9081
I need to filter a collection of items by verifing the value of a flag named 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.
How can I fix this method?
Upvotes: 2
Views: 3438
Reputation: 205539
Instead of reflection, you can build the filter expression manually using System.Linq.Expressions
like this:
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
. But the same can be said for your reflection based implementation (if it worked).
Upvotes: 10
Reputation: 151588
An ORM will inspect the lambda and convert its parts to 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.
It wouldn't work anyway, because GetProperty()
gets a PropertyInfo
instance, not the value. So if it were null
, that would indicate that the type of p
has no property named 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):
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:
public class WhateverClass<T>
where T : IDeletable
{
public List<T> GetAll()
{
return context.Set<T>().Where(p => p.deletion_date == null).ToList();
}
}
Upvotes: 3