Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
401 views
in Technique[技术] by (71.8m points)

c# - Dont know how to loop through types in DbContext calling ToListAsync generically


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The ToListAync() is in the class EntityFrameworkQueryableExtensions, so

var method = typeof(EntityFrameworkQueryableExtensions).GetMethod(nameof(EntityFrameworkQueryableExtensions.ToListAsync)).MakeGenericMethod(typeof(Country));

and it is static, so:

var result = method.Invoke(null, new object[] { this.Countries, default(CancellationToken) });

Where result is a Task<List<Country>> that is a Task.

To call it is hard :-) Technically calling the method is easy... extracting the result is hard. If you want to go full-dynamic it gets hard quickly:

var t = (Task)method.Invoke(null, new object[] { context.Blogs, default(CancellationToken) });
await t;
var ilist = (IList)((dynamic)t).Result;

and now you a non-generic IList, so its elements are object. But in the end you are going in the wrong direction. If you want to go in the "right" direction, make a :

public static async void DoWorkOnMyIQueryable<T>(IQueryable<T> dbset)
{
    List<T> res = await dbset.ToListAsync();

    foreach (var el in res)
    {
        // Do something
    }
}

and call the DoWorkOnMyIQueryable through reflection. Now at least you have a typed List<T>!

Now that you have written your full question, as often it is, it was an XY problem.

As I've written, it is much easier to build a single generic method that is based around a generic TEntity and then use reflection to call it.

The method:

public static class Tools
{
    public static async Task<IList> ExtractData<TEntity>(DbContext context, List<FilterObject> filters) where TEntity : class
    {
        var dbset = context.Set<TEntity>();
        var filter = EntityQueryFilterHelper.CreateFilter<TEntity>(filters);
        var filtered = filter(dbset);

        return await filtered.ToListAsync();
    }
}

And now to call it:

public async Task<Dictionary<string, IList>> GenerateContextDictionary()
{
    var filters = new List<FilterObject>();
    // Here prepare your filters

    var entityTypes = this.Model.GetEntityTypes().Where(x => x.Name.Contains("Country"));

    var method = typeof(Tools).GetMethod(nameof(Tools.ExtractData), BindingFlags.Public | BindingFlags.Static);

    var contextDictionary = new Dictionary<string, IList>();

    foreach (var entityType in entityTypes)
    {
        var method2 = method.MakeGenericMethod(entityType.ClrType);
        var ilist = await (Task<IList>)method2.Invoke(null, new object[] { this, filters });
        contextDictionary.Add(entityType.Name, ilist);
    }

    return contextDictionary;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...