2

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?

1
  • Don't use reflection,even less with linq-to-entities which doesn't support it. Why don't you have a method GetAllUsers and one GetAllFoo and so on`? Commented Mar 11, 2016 at 15:57

2 Answers 2

10

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).

Sign up to request clarification or add additional context in comments.

Comments

3

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();
    }
}

6 Comments

thank you. I can't implement the interface IDeletable interface for all the T because the T class are auto-generated(from edmx)
You can, because they are generated as partial classes.
But I have to edit it in every re-generation of the model !!
No, you don't, they are partial classes. Create a new file, using the same namespace as your EDMX entities, in which you create partial classes like public partial class SomeEntity : IDeletable { } and you're good to go. Try searching, see for example Generating Interfaces from entity framework database first auto-generated code.
Yes I know but assume I add couples of entities to the model so I have to add the implementation of the interface for the new class everytime
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.