Search code examples
c#linqentity-framework-6odatabreeze

Linq where-filter causes cast to base class


I have a generic IQueryable of a concrete class:

IQueryable<Person> result = GetAllEmployees(); //returns IQueryable<Employee>

If I return result in a service-call for a Breeze-Entitytype, everything works fine:

breeze.EntityQuery.from("Employees").orderBy("EmployeeID");

As soon as I add a where-filter to the result in the service-call, the whole IQueryable-Object seems to be casted to the base class Person and not have a property EmployeeID anymore:

IQueryable<Person> result = GetAllEmployees(); //returns IQueryable<Employee>
result = result.Where(o => myHashSet.Contains(o.Id));

This causes the following Error:

Microsoft.Data.OData.ODataException: The query specified in the URI is not valid. Could not find a property named 'EmployeeID' on type 'Person'.

Solution

  • Apparently the where wrapps the IQueryable into a new IQueryable of the type of the variable it is stored in. The ElementType of the original IQueryable is lost.

    You can see this when you break at the where and inspect result.ElementType. As soon as you step over the where it changes from Employee to Person.

    With the following Code we restore the ElementType (feed it with result.ElementType from before the where):

    public static IQueryable<T> ToTypedQueryable<T>(this IEnumerable<T> source, Type theType, bool exact = false) {
        if (source == null) throw new ArgumentNullException("source");
    
        System.Collections.IList result = (System.Collections.IList)typeof(List<>)
            .MakeGenericType(theType)
            .GetConstructor(Type.EmptyTypes)
            .Invoke(null);
    
        foreach (var s in source) {
            Type t = s.GetType();
            if (t == theType) {
                result.Add(s);
            } else if (!exact && t.IsSubclassOf(theType)) {
                result.Add(s);
            }
        }
    
        return (IQueryable<T>)(result.AsQueryable());
    }