user1209216
user1209216

Reputation: 7914

Entity framework - get entity by name

I have the following code (example):

public dynamic GetData(string name) 
{
    using(var ctx = GetObjectContext()) 
    {
        switch (name) 
        {
        case "entity1":
            return ctx.entity1.ToList();
        case "entity2":
            return ctx.entity2.ToList();
        ......
        default:
            return null;
        }
    }
}

I want to avoid switch in this sample. How can I find needed entity class by name, call the ToList() method and return data? Can I do this using reflection?

Upvotes: 19

Views: 37865

Answers (3)

James.mikael
James.mikael

Reputation: 99

I've created a method to include all related entities with some help of the great answer of @chiccodoro.

Using the entity "Product" which has 7 navigation properties

public static IQueryable<T> IncludeAllEntities<T>(this DbSet<T> entity, DataContext context) where T : class
{
        var queryable = entity.AsQueryable();

        var type = typeof(T);
        var entityType= context.Model.FindEntityType(type);
        var navs = entityType?.GetNavigations();

        if (navs == null)
        {
            return null;
        }

        List<string> navNames = new List<string>();

        foreach (var nav in navs)
        {
            navNames.Add(nav.Name);
        }

        try
        {
            var agg = navNames.Aggregate(queryable, (acc, name) => acc.Include(name));
            return agg;
        }
        catch (Exception ex)
        {
            throw;
        }
}

I am getting the type of the entity to get the navigation properties, then adding the name of each one to a list of string, then aggregating over the list to include each entity.

Then we can use this extension method like this:

var record = await _context.Products
                           .IncludeAllEntities(_context)
                           .FirstOrDefaultAsync(x => x.Id == key);

Upvotes: 0

Oleg Polezky
Oleg Polezky

Reputation: 1132

You can use code like this

private IEnumerable<TEntity> GetList<TEntity>(string connectionString, Func<object, T> caster)
{
    using (var ctx = new DbContext(connectionString))
    {
        var setMethod = ctx.GetType().GetMethod("Set").MakeGenericMethod(typeof(T));

        var querable = ((DbSet<object>)setMethod
        .Invoke(this, null))
        .AsNoTracking()
        .AsQueryable();

        return querable
            .Select(x => caster(x))
            .ToList();
    }
}

To call like this:

var branchList = GetList<Branch>("connectionStringName", x => (Branch)x);

You can remove .AsNoTracking() and remove .ToList(), then you will get pure IQueryable which you can query further.

Upvotes: 1

chiccodoro
chiccodoro

Reputation: 14716

You can do it using reflection, however you will also need to use generics because the type of list returned by the ToList() method is different for each entity type.

You can access a property getter through reflection like so:

var enumerable = typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null);

Whereas [ClassNameOfContext] is the name of the class that ctx is an instance of. This is not obvious from your code, but you know it :-)

The problem is that enumerable will be an object and has to be casted to IEnumerable<EntityType> where EntityType is the type of entity you are accessing. In other words, it depends on the name you are passing. If you use generics to determine the type, you will be able to properly cast the object and don't have to return a dynamic even.

public TEntity Get<TEntity>(string name)
{
    ...

and transform the line from above:

var enumerable = (IEnumerable<TEntity>)(typeof([ClassNameOfContext]).GetProperty(name).GetValue(ctx, null));
return enumerable.ToList();

here you go!

Addendum: You could, conceivably, get rid of the string parameter, too - having names of types or properties in strings should be avoided where possible because it is not type safe. The compiler does not recognize it, and IDE features such as refactorings don't account for it. The problem here is that the property names are usually the pluralized form of the entity type names. But you could use reflection to find the property whose type matches the TEntity. I leave this as an exercise :-)

Upvotes: 24

Related Questions