linqentity-frameworkdynamicpocodynamic-class

ParseException: No property or field '???' exists in type 'DynamicClass' when using GroupBy and Select


I'm using EntityFramework together with System.Linq.Dynamic and I've defined Employee POCO class as follows:

public class Employee
{
    public long Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Company Company { get; set; }
    public Country Country { get; set; }
}


I'm using this code to do a GroupBy the Country Name:

var query = Employees.Include(e => e.Company).Include(e => e.Country);  
var groupByQuery = query.GroupBy("new (Country.Code as GroupByField)", "new (it AS XEmployee, it.Company AS XCompany, it.Country AS XCountry)");
var selectQuery = groupByQuery.Select("new (Key.GroupByField, it as Grouping)");
var grouping = selectQuery.Select("it.Grouping") as IQueryable<IGrouping<DynamicClass, DynamicClass>>;
var objects = grouping.First().AsQueryable() as IQueryable<object>;

// This line gives me : ParseException: No property or field 'XEmployee' exists in type 'DynamicClass'
var employees = objects.Select("it.XEmployee");

It's very strange because when I dump all the properties from the DynamicClass, the XEmployee is a valid public property ?

var firstObject = objects.First();
firstObject.GetType().GetProperties().Dump();

Shows enter image description here


Solution

  • I've created an extension method which gets a property from an object and casts this to the required type.

    See this code for the extension method "Select"

    public static class DynamicQueryableExtensions
    {
       public static IEnumerable<TEntity> Select<TEntity>(this IEnumerable<object> source, string propertyName)
       {
           return source.Select(x => GetPropertyValue<TEntity>(x, propertyName));
       }
    
       private static T GetPropertyValue<T>(object self, string propertyName)
       {
           var type = self.GetType();
           var propInfo = type.GetProperty(propertyName);
    
           try
           {
               return propInfo != null ? (T)propInfo.GetValue(self, null) : default(T);
           }
           catch
           {
               return default(T);
           }
       }
    }
    

    The code is used as follows:

    // This line will just work fine.
    var employees = objects.Select<Employee>("XEmployee");
    employees.Dump();
    


    For a working example, see my KendoGridBinderEx project on github.