1

I'm trying to implement some filtering in my Dynamic Data + EF website and I'm using a QueryExtender with a CustomExpression. In the OnQuerying event of the CustomExpression I have access to e.Query(where e is of type CustomExpressionEventArgs) which is the Query that is used to get the data from the database. In order to filter the data I need to make changes to this query.

Now this query is of type System.Data.Objects.ObjectQuery<T>, where T is only known at runtime. I'm going to assume that whatever type T is, it's going to have a property called GameId. What I need to do is do a simple Where LINQ statement on this collection where I filter by that property.

short GameId = Convert.ToInt16(Session["GlobalGameFilter"]);
Type currentType = e.Query.ElementType;
//ObjectQuery implements IQueryable and I want to cast to ObjectQuery<CurrentType> 
MethodInfo method = typeof(Queryable).GetMethod("Cast").MakeGenericMethod(new Type[] { currentType });
var castedQuery = method.Invoke(e.Query, new object[]{e.Query});

This works, now castedQuery is of type ObjectQuery<currentType>

The problem is that in order to use castedQuery.Where() I need to cast it to an IEnumerable<currentType>, I can't just cast it to the non-generic IEnumerable.

I tried calling Where via reflection (from here):

var whereMethods = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Where");
MethodInfo whereMethod = null;
foreach (var methodInfo in whereMethods)
{
    var paramType = methodInfo.GetParameters()[1].ParameterType;
    if (paramType.GetGenericArguments().Count() == 2)
    {
        whereMethod = methodInfo;
    }
}

whereMethod = whereMethod.MakeGenericMethod(currentType);

var ret = whereMethod.Invoke(castedQuery, new object[] { castedQuery, BuildEqFuncFor<Placement>("GameId", GameId) });

But ret is always an empty collection.

Edit: You can see that I hardcoded the type in that last line to be placement (just for testing), but I'd need that to be currentType of course.

Edit2: If I try this

foreach(var item in castedQuery as IEnumerable)
{
    var itemGameId = item.GetType().InvokeMember("GameId", BindingFlags.GetProperty, null, item, null);
}

it works, itemGameId actually gets the gameId that i need so the problem must be that the predicate is not being used correctly.

Edit 3: Tried implementing a common interface

public interface IGameId
{
    short GameIdGetter { get; }
}
public partial class Placement : IGameId
{
    public short GameIdGetter
    {
        get
        {
            return this.GameId;
        }
    }
}

e.Query = e.Query.Cast<IGameId>().Where(x => x.GameIdGetter == GameId);

Get an error here when I try to enumerate e.Query : {"Unable to cast the type 'OfferManagementBackOffice.Placement' to type 'OfferManagementBackOffice.IGameId'. LINQ to Entities only supports casting EDM primitive or enumeration types."}

Community
  • 1
  • 1
Adrian Buzea
  • 826
  • 2
  • 11
  • 33
  • It's hard to know which exact step is causing a problem - for example, whether it's all working fine, and it's just that your where predicate never matches. It would really help if you'd show a short but complete program demonstrating the problem. – Jon Skeet Sep 01 '15 at 08:19
  • you are looping did you try to break the loop when condition already satisfied? it seems that `whereMethod` is always overwritten – Anonymous Duck Sep 01 '15 at 08:20
  • Would it help to have an `IGameID` interface? – Ross Presser Sep 01 '15 at 08:21
  • there's more than one where method, I just need to get the right one. That part is fine. – Adrian Buzea Sep 01 '15 at 08:21
  • try to breakpoint your code. – Anonymous Duck Sep 01 '15 at 08:22
  • I agrred with @Ross Presser as you said "I'm going to assume that whatever type T is, it's going to have a property called GameId. " so better make a base class and then voila – Amit Tiwari Sep 01 '15 at 08:24
  • I'd prefer an interface, not a base class, but YMMV. – Ross Presser Sep 01 '15 at 08:24
  • How would that help me? The problem is that I can't get the where to work correctly. Also, I cannot debug the Func that is used as a predicate cause it uses a lambda expression. I'm pretty sure the problem is the predicate, because when debugging I can see that the castedQuery contains all of the query elements casted to the correct type so it's probably never matching the predicate for some reason – Adrian Buzea Sep 01 '15 at 08:30
  • 1
    Because you make your query `System.Data.Objects.ObjectQuery` and it's much easier from there. – Flynn1179 Sep 01 '15 at 08:45
  • The problem is that my classes are generated automatically by EF, so I can't really change them to implement that interface because if I ever change my model they will get overwritten – Adrian Buzea Sep 01 '15 at 08:53
  • Does/can EF's generation use `partial class`? (I don't know without checking), if it did you could have separate `partial class` declarations saying they implement the interface. – Jon Hanna Sep 01 '15 at 08:56
  • It does, and I tried it (edited the original post) but still doesn't work. – Adrian Buzea Sep 01 '15 at 09:10

0 Answers0