1
\$\begingroup\$

I wrote an EF browser to dynamically navigate through entities. Beside basic properties of system types, each entity can have several singular or plural navigation properties. In order to support all of these using a single batch of code, I come up with the following solution considering the following requirement:

  • Each entity has an integer ID primary key.

Sample query strings (Person is an entity (ID = 10) with Job and Cars navigation property):

Person/10/Job

Person/10/Cars

Solution:

public List<dynamic> LoadEntitiesByQuery(String query) {

    String[] parts = query.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
    String entityName = parts[0];
    int id = int.Parse(parts[1]);
    String subEntityName = parts[2];

    Type entityType = GetTypeFromEntityName(entityName);

    var tempObj = db.Set(entityType)
                    .AsQueryable()
                    .Where(String.Format("ID == {0}", id))
                    .FirstOrDefault();

    var propertyInfo = tempObj.GetType().GetProperty(subEntityName);

    List<dynamic> objects;

    if (propertyInfo.PropertyType.IsGenericType)
        objects = ((IEnumerable<dynamic>)propertyInfo.GetValue(tempObj, null)).ToList();
    else
    {
        var tr = propertyInfo.GetValue(tempObj, null);
        objects = new List<dynamic>();
        objects.Add(tr);
    }

    return objects;
}

internal static Type GetTypeFromEntityName(string entityName)
{
    Type entityType = null;
    switch (entityName)
    {
        case "Person":
            entityType = typeof(Person);
            break;
        case "Job":
            entityType = typeof(Job);
            break;

        ///  ....
    }
    return entityType;
}

I'm looking for faster ways of doing dynamic query instead of reflection.

\$\endgroup\$
1
\$\begingroup\$
  1. I would write an extension method to do parsing of input string. so it should not be inside your query method.

  2. I have declared a class named SearchCriteria to encapsulate all data member you want t o query.

this is just a first set of refactoring which should be included.

public class SearchCriteria
{
    public Type EntityType { get; set; }

    public string SubEntityName { get; set; }

    public int EntityId { get; set; }

}

public static class ParseExtension
{
    public static SearchCriteria Parse(this string query)
    {
        string[] parts = query.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
        var entityName = parts[0];
        var id = int.Parse(parts[1]);
        var subEntityName = parts[2]; 

        return new SearchCriteria
        {
            EntityType = GetTypeFromEntityName(entityName),
            EntityId = id,
            SubEntityName = subEntityName
        };
    }

    private static Type GetTypeFromEntityName(string entityName)
    {
        Type entityType = null;
        switch (entityName)
        {
            case "Person":
                entityType = typeof(Person);
                break;
            case "Job":
                entityType = typeof(Job);
                break;
        }
        return entityType;
    }
}


public List<dynamic> LoadEntitiesByQuery(SearchCriteria query)
{
    Type entityType = query.EntityType;

    var tempObj = db.Set(entityType)
                    .AsQueryable()
                    .Where(string.Format("ID == {0}", query.EntityId))
                    .FirstOrDefault();

    var propertyInfo = tempObj.GetType().GetProperty(query.SubEntityName);

    List<dynamic> objects;

    if (propertyInfo.PropertyType.IsGenericType)
        objects = ((IEnumerable<dynamic>)propertyInfo.GetValue(tempObj, null)).ToList();
    else
    {
        var tr = propertyInfo.GetValue(tempObj, null);
        objects = new List<dynamic>();
        objects.Add(tr);
    }

    return objects;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.