Max Favilli
Max Favilli

Reputation: 6449

Call EF Core method with generic type from type name

I have an application logging a list of query to be executed at a later time. So I have a list containing something like this:

class QueryToBeExecutedLater
{
    string sql { get; set; }
    object[] parameters { get; set; }
    string entityTypeFullName { get; set; }
}

And I need to execute them like:

List<QueryToBeExecutedLater> allQueries = ...

foreach(var q in allQueries )
{
    Type elementType = Type.GetType(q.entityTypeFullName);
    var result = await db.Set<elementType>.FromSqlRaw(q.sql,q.parameters).ToListAsync();
}

But of course it doesn't work.

I am not all that familiar with reflection. So far I have been able to get the dbSet with this:

List<QueryToBeExecutedLater> allQueries = ...

foreach(var q in allQueries )
{
    Type elementType = Type.GetType(q.entityTypeFullName);
    MethodInfo method = typeof(myDbContext).GetMethod("Set",
                                  BindingFlags.Public | BindingFlags.Static);
    method = method.MakeGenericMethod(elementType);
    var _dbSet = method.Invoke(db,null);

    var result = _dbSet.FromSqlRaw(q.sql,q.parameters);
}

Which of course doesn't work, because:

enter image description here

I probably should be doing something like this:

List<QueryToBeExecutedLater> allQueries = ...

foreach(var q in allQueries )
{
    Type elementType = Type.GetType(q.entityTypeFullName);
    MethodInfo method = typeof(myDbContext).GetMethod("Set",
                                  BindingFlags.Public | BindingFlags.Static);
    method = method.MakeGenericMethod(elementType);
    var _dbSet = method.Invoke(db,null);

    var typeReturnedByInvoke_type_of_dbset = **...How Do I Get this type?...**
    MethodInfo _method = typeReturnedByInvoke_type_of_dbset.GetMethod("FromSqlRaw",
                                  BindingFlags.Public | BindingFlags.Static);

    object[] frontParameter = { sql };
    var allParameters = frontParameter.Concat(parameters).ToArray();

    // The "null" is because it's a static method
    var result = _method.Invoke(_dbSet, allParameters);
}

But how do I get the type of the result of method.Invoke?

Or is there a way to avoid all these invokes and just cast the result of the first invoke to the right DbSet<elementType> and continue from there without reflection?

Thank you in advance for any help!

Upvotes: 1

Views: 1923

Answers (1)

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89361

You've figured out how to call a single generic method through reflection, and that's all you need. Just introduce a RunQuery<TEntity> and call that.

EG

    public static List<object> RunQuery(QuerySpec query, DbContext db)
    {
        Type elementType = Type.GetType(query.entityTypeFullName);
        var rv = typeof(Program).GetMethod("RunQuery2", BindingFlags.Static | BindingFlags.NonPublic)
                                .MakeGenericMethod(elementType)
                                .Invoke(null, new object[] { query, db });
        return (List<Object>)rv;

    }
    private static List<object> RunQuery2<T>(QuerySpec query, DbContext db) where T : class
    {
        var rv = db.Set<T>().FromSqlRaw(query.sql, query.parameters)
                   .Select( e=>(object)e )
                   .ToList();
        return rv;
    }

Upvotes: 5

Related Questions