Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF get list of records in runtime from Type

Purpose: I need to loop all records like:

var records = db.Set<UserAccount>().ToList();

Then loop

foreach (var record in records)
{
    // do something with the record 
}

But it has to not type specific in runtime, as I am to loop through types and therefor do not know example "UserAccount". Only the Type/TypeOf?

In the bottom of this description I have a method loopAllEntities that I cannot find a way to work

I have created an DbContext with some entities.

public class MyEntities : DbContext
{
    public DbSet<UserAccount> UserAccounts { get; set;}
    public DbSet<UserRole> UserRoles { get; set; }
    public DbSet<UserAccountRole> UserAccountRoles { get; set; }
}

Defined a list of Type to control the output:

public static List<Type> ModelListSorted()
{
    List<Type> modelListSorted = new List<Type>();
    modelListSorted.Add(typeof(UserRole));
    modelListSorted.Add(typeof(UserAccountRole));
    modelListSorted.Add(typeof(UserAccount));
    return modelListSorted;
}

The problem is below where I cannot find a way to make it Work :-(

public static loopAllEntities()
{
    List<Type> modelListSorted = ModelHelper.ModelListSorted();

    foreach (Type type in modelListSorted) 
    {           
        var records = ????? // get a list of records in the current table from type.
        foreach (var record in records)
        {
            // do something with the record
        } 
    }
}
like image 382
pladekusken Avatar asked Oct 21 '14 18:10

pladekusken


2 Answers

I know this is an old question, yet the question does not specify EF version and the proposed answer does not work anymore for Entity Framework Core (DbContext does not have non-generic set method in EF core at least at the date of this answer).

Yet you can still have a working extension method using the answer of Jon Skeet to this question. My code is added below for convenience.

    public static IQueryable Set(this DbContext context, Type T)
    {

        // Get the generic type definition
        MethodInfo method = typeof(DbContext).GetMethod(nameof(DbContext.Set), BindingFlags.Public | BindingFlags.Instance);

        // Build a method with the specific type argument you're interested in
        method = method.MakeGenericMethod(T);

        return method.Invoke(context, null) as IQueryable;
    }
like image 65
user3141326 Avatar answered Oct 06 '22 01:10

user3141326


It looks like you are almost there, you should be able to do something like the following:

    public static void loopAllEntities(DbContext dbContext)
    {
        List<Type> modelListSorted = ModelHelper.ModelListSorted();

        foreach (Type type in modelListSorted) 
        {
            var records = dbContext.Set(type);
            // do something with the set here
        }
    }

This will get you a non generic set to work with. It depends from there what you want to do as there is no type to this set it can get a bit tricky, maybe cast to a base type or interface to work with?

Edit: I don't have enough reputation to comment, but Mayoors solution would get you what you want without using a non-generic type and get the whole collection up front.

like image 27
Matt Sanders Avatar answered Oct 05 '22 23:10

Matt Sanders