4

I am trying to figure out how to select values from a lookup table using generics and at run time pass the entity name as a string. Here is what I have so far. The problem I'm having is in the "var codes = Select();" line. As you can guess, the compiler is not happy and is giving me an error of: classType is a variable but used as a type. I'm not sure what to do or how to fix it. I can't hardcode an interface or class name as I don't know the signature of the code table until the string is resolved. Any guidance would be greatly appreciated!

public void GetTableNameObject(string TableName)
{
    dynamic classType = Activator.CreateInstance(Type.GetType(TypeName));
    var codes = Select<classType>();
}

public IQueryable<TItem> Select<TItem>() where TItem : class, new()
    {
        PropertyInfo property = GetDbSet(typeof(TItem));    
        DbSet<TItem> set = property.GetValue(_context, null) as DbSet<TItem>;    
        return set;
    }

    private PropertyInfo GetDbSet(Type itemType)
    {
        var properties = typeof(CodeTableContext).GetProperties().Where(item => item.PropertyType.Equals(typeof(DbSet<>).MakeGenericType(itemType)));

        return properties.First();
    }
Gr8Sarge
  • 43
  • 4
  • Are your table names different from entity names ? and what do you mean by `lookup table` ? – Ashkan Jun 19 '16 at 14:43

2 Answers2

1

Yes, that's cause classType is a dynamic variable and generic method type T must be closed at compile time and can't be keep opened since the type gets resolved at compile time itself.

In your case, as mentioned earlier classType is a dynamic variable and will be resolved only in runtime and thus you just can't pass it as type to generic method since compiler won't be able to resolve it at compile.

You might want to use Reflection for this purpose and take a look at this post How do I use reflection to call a generic method?.

(OR) Instead of a dynamic type, try casting it to any of your base type like (not sure though since have no idea about your class hierarchy)

IMyBase classType = Activator.CreateInstance(Type.GetType(TypeName)) as IMyBase;
Community
  • 1
  • 1
Rahul
  • 76,197
  • 13
  • 71
  • 125
0

I think what you are trying to do is to find a DbSet in an entity framework DbContext object giving its entity's name (assuming that your entity names aren't different from your table names or somehow you can achieve one by means of the other one). You cannot use a generic method like Select<TItem> where ... because it would need you to know the type of TItem at compile time (meaning when writing your code).

The more important problem is that you are trying to undo what entity framework has done for you! EF has made everything (tables and columns) strongly typed for you but you don't want that and are going back to use strings and literals like what it was when we used ADO.Net. I'm inclined to suggest you to use SQL commands and make your query using SQL statements but it depends on your application and that when this method would be called and so many other factors.

In fact there is multiple options that you can get your DbSet from your entity name, one of them is that you create a dictionary of your entity names mapped to expressions which returns the corresponding DbSet but again when you don't know the type in compile type it would not be very usable, meaning you can't use linq on that db set because linq uses strongly typed syntax. Anyway this is what I suggest which is not a great solution but it works:

Dictionary<string, Func<CodeTableContext, DbSet>> entityDbSetMap = new Dictionary<string, Func<EFDB, DbSet>>
{
    { "ProductEntity", (db) => db.ProductEntities },
    { "OrderEntity", (db) => db.OrderEntities },
    { "FooEntity", (db) => db.FooEntities },
    { "BarEntity", (db) => db.BarEntities },
    // more mappings ......
}

public IQueryable GetTableNameObject(string EntityName)
{
    DbSet dbset = entityDbSetMap[entityName](_context);
    return dbset.AsQueryable();
}

This way you can only use a dynamically created expression on the queryable object which is obtained, which might be what you want to do.

Hope this helps.

Ashkan
  • 3,322
  • 4
  • 36
  • 47