I would like to pass an IQueryable and an array of ids to a method which filters the IQueryable based on those ids.
As the ids can be either long's or int's it should be solved generically.
I came up with the following:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}
Unfortunately I'm getting the exception:
LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object)' method, and this method cannot be translated into a store expression.
Entity Framework doesn't support some of the .NET methods such as
GetValue()
since it does not translate to SQL (which is the code actually executed to theIQueryable
. Try callingToList
to get the CLR object before doing reflection:The exception is normal, as getting properties through reflection is something that clearly cannot be translated to SQL.
One thing I would try is to create a generic interface that exposes an
Id
property of a given type:Now you could declare your entity as implementing
HasId<int>
, for example, if theId
was of typeint
.The next step is to modify your method like so:
Note the added generic restriction:
where T : class, HasId<TId>
. This enables you to write the simplifiedj.Id
, which returns aTId
value, instead of resorting to reflection.Please note that I haven't run or tested this code; it's just an idea that I got when I saw your problem and I hope it helps.
Update:
Here's another possible solution that doesn't require that you declare interfaces or change your classes in any way:
What I've done here is add the
Expression<Func<T, TId>> idSelector
parameter, an expression that can return theId
of a given instance ofT
.You would call the method like that:
(only the third parameter being new; keep the others as you have them now).
Again, I haven't tested if this works or even compiles, as I don't have a computer with VS here :(.