Reputation: 961
I'm trying to dynamically switch out my table annotations' schema values @ Runtime when using EF6.
So here's what I've got thus far:
var builder = new DbModelBuilder()
var dbSetProperties = typeof(T).GetProperties().Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>));
foreach (PropertyInfo property in dbSetProperties)
{
Type[] propTypes = property.PropertyType.GetGenericArguments();
// Iterate the DbSets and set the correct schema
foreach (Type dbSetType in propTypes)
{
// Get the TableAttribute
var tableAttribute = Attribute.GetCustomAttribute(dbSetType, typeof(TableAttribute));
MethodInfo dbModelMethodInfo = typeof(DbModelBuilder).GetMethod("Entity");
MethodInfo entityTypeConfigMethodInfo = typeof(EntityTypeConfiguration<>).GetMethod("ToTable", new[] { typeof(String), typeof(String) });
MethodInfo genericDbModelMethodInfo = dbModelMethodInfo.MakeGenericMethod(dbSetType);
genericDbModelMethodInfo.Invoke(builder, null);
entityTypeConfigMethodInfo.Invoke(genericDbModelMethodInfo, new Object[] { (tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE" });
}
}
What I'm trying to accomplish is something like this (which doesn't work):
builder.Entity<dbSetType>().ToTable((tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE");
Basically, for T I want to pull the DbSets, determine the Class used in the Entity<> generic, get the TableAttribute, and set the Schema to a new value.
Currently, on entityTypeConfigMethodInfo.Invoke, I'm getting an error of "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true".
What am I missing?
Upvotes: 1
Views: 188
Reputation: 583
Since EntityTypeConfiguration is a generic Type , could you specify the type of Generic parameter being used in your object for EntityTypeConfiguration. Ex :
Type type= typeof (GenericClass<>).MakeGenericType(typeof(int));
Here 'GenericClass' is a generic class with generic 'T' parameter. I have specified int type while getting the type information of it. Then Invoke the method on this type will work fine.
I have written a sample code which does the same, but minimally what you are trying to do and may help you solve your error.
class Program
{
static void Main()
{
Type type= typeof (GenericClass<>).MakeGenericType(typeof(int));
var method = type.GetMethod("TestMethod");
var instance = Activator.CreateInstance(type);
method.Invoke(instance, null);
}
}
public class GenericClass<T> where T : struct // These parameters can be anything
{
public T TestMethod()
{
T a = new T();
return a;
}
}
Upvotes: 0
Reputation: 4218
To get the right closed generic methodinfo for the second call you rewrite your code to:
MethodInfo genericDbModelMethodInfo = dbModelMethodInfo.MakeGenericMethod(dbSetType);
MethodInfo entityTypeConfigMethodInfo = genericDbModelMethodInfo.ReturnType.GetMethod("ToTable", new[] { typeof(String), typeof(String) });
Then you have to use the return value of the genericDbModelMethodInfo.Invoke
call as the first parameter in the second call.
var obj = genericDbModelMethodInfo.Invoke(builder, null);
entityTypeConfigMethodInfo.Invoke(obj, new Object[] { (tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE" });
That is because the first parameter in MethodInfo.Invoke
is the object you want to invoke the method on.
Upvotes: 1
Reputation: 391346
Well, yes, what did you expect?
You say you get the error on this line:
entityTypeConfigMethodInfo.Invoke(genericDbModelMethodInfo, new Object[] { (tableAttribute as TableAttribute).Name, "NEW_SCHEMA_VALUE" });
The problem is not with this line, but with this line:
MethodInfo entityTypeConfigMethodInfo = typeof(EntityTypeConfiguration<>).GetMethod("ToTable", new[] { typeof(String), typeof(String) });
You're getting the method ToTable
of which type?
The type containing that method is still an open generic type. You must specify the type arguments to make it a specific type, then you can get the method to invoke.
In other words, you need this:
MethodInfo entityTypeConfigMethodInfo =
typeof(EntityTypeConfiguration<>).MakeGenericType(...).GetMethod("ToTable", new[] { typeof(String), typeof(String) });
^-------------------^
Upvotes: 3