Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Dynamic DbSet for all entities

I have a database mapped with Entity Framework,

I need to implement a generic method for getting a a list of items based on a parameter that I pass:

getGenericList("product"); // returns the list of products
getGenericList("customer"); // returns the list of customers

I need to dynamically get the dbSet. My method is implemented like this:

public static List<object> getGenericList(string entityType)
    {
        List<object> myDynamicList = new List<object>();
        using (cduContext db = new cduContext())
        {
            DbSet dbSet = db.getDBSet(entityType);
            var myDynamicList = dbSet.Select(p => p).ToList();
        }
        return new List<object>();
    }

my dbSets are auto-generated by EF code first :

public DbSet<Product> Products { get; set; }
public DbSet<Custommer> Custommers { get; set; }

my getDBSet(entityType) method is implemented in the context, like this:

public DbSet<T> getDBSet<T>(string entityName) where T : class
    {
        switch (entityName)
        {

            case "product":
                return Products;

            case "custommer":
                return Custommers;

I then got this error:

Cannot implicitly convert type 'System.Data.Entity.DbSet' to 'System.Data.Entity.DbSet'

Any Idea please !?

N.B. , the method Set() of the dbContext is not OK; the type should be explicitly given ...

like image 420
SirZoro Avatar asked Oct 05 '22 09:10

SirZoro


1 Answers

It's better to stay away from strings as types and mapping them to real types; that's a code smell. Instead, use the types themselves. Either way, let's refactor your code that uses the getGenericList() method to use generics. If you can't get away from strings, do the mapping in the code that calls getGenericList() as opposed to mapping inside that method, since we're following the pattern you've set forth.

Also note that in your original getGenericList() you're always returning an empty list, as opposed to the list you obtained via EF. You're also using 2 different myDynamicList variables; the outer one is masked by the one in the scope of the using statement which is why you don't get a compiler error. Once the using goes out of scope, the inner myDynamicList goes out of scope too. I've addressed that here.

public static List<T> getGenericList<T>()
{
    List<T> myDynamicList;

    using (cduContext db = new cduContext())
    {
        // consider using exception handling here as GetDbSet might get an invalid type
        DbSet dbSet = db.GetDbSet<T>();
        myDynamicList = dbSet.Select(p => p).ToList();
    }

    if (myDynamicList != null && myDynamicList.Count() > 0)
    {
        return myDynamicList;
    }
    return new List<T>();
}

// in your context class
public DbSet<T> GetDbSet<T>() where T : class
{
    return this.Set<T>();
}

// this is the code that calls getGenericList(); put this inside a function somewhere. 
// entityName holds a string value, set previously
switch(entityName.ToLower()) // making entityName case insensitive
{
    case "product":
        return getGenericList<Product>();

    case "customer":
        return getGenericList<Customer>();
}

Hopefully you won't have too many entity types that you want to map, or you'll end up with a huge switch statement. Again, if you're using a switch statement, in general it's probably an indication that you need to re-think your approach.

like image 134
bcr Avatar answered Oct 13 '22 11:10

bcr