Dynamically Building a Model with Code First
I’ve answered a few emails recently on this topic so it felt like time to turn it into a blog post.
In this scenario the set of classes that make up your model isn’t known at compile time and is discovered dynamically at runtime. An example of such a scenario is a WordPress/Orchard/etc. style website that allows modules to be plugged in. These modules live in a separate assembly and may contain classes that represent data to be persisted in the application database. These classes are all pulled into a central Code First model to be used for data access.
Finding the Classes
There are lots of different approaches for identifying the classes to be included in the model. For this example lets use a [Persistent] attribute, something like this:
[AttributeUsage(AttributeTargets.Class)] public class PersistentAttribute : Attribute { }
Now we can add some logic to the OnModelCreating method of our context to scan assemblies and add any classes with the [Persist] attribute. We’re going to assume that the assemblies that may contain classes are all loaded into the current AppDomain, of course you may have some other mechanism that provides a list of the assemblies to check.
public class MyContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { var entityMethod = typeof(DbModelBuilder).GetMethod("Entity"); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { var entityTypes = assembly .GetTypes() .Where(t => t.GetCustomAttributes(typeof(PersistentAttribute), inherit: true) .Any()); foreach (var type in entityTypes) { entityMethod.MakeGenericMethod(type) .Invoke(modelBuilder, new object[] { }); } } } }
In this example the entire model is dynamically discovered, but you could also have some static parts of the model that are registered with modelBuilder too.
An Alternative Using EntityConfiguration<TEntity>
Code First allows you to create a class that derives from EntityTypeConfiguration<TEntity> to encapsulate the Fluent API configuration for an entity. If your using this approach to configuration you can just look for these configuration classes and register them, instead of finding the entities to register. Notice that we are filtering out the EntityFramework assembly since it has some configuration classes that it uses internally.
public class MyContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { var addMethod = typeof(ConfigurationRegistrar) .GetMethods() .Single(m => m.Name == "Add" && m.GetGenericArguments().Any(a => a.Name == "TEntityType")); foreach (var assembly in AppDomain.CurrentDomain .GetAssemblies() .Where(a => a.GetName().Name != "EntityFramework")) { var configTypes = assembly .GetTypes() .Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in configTypes) { var entityType = type.BaseType.GetGenericArguments().Single(); var entityConfig = assembly.CreateInstance(type.FullName); addMethod.MakeGenericMethod(entityType) .Invoke(modelBuilder.Configurations, new object[] { entityConfig }); } } } }
What if the Model Changes?
Code First Migrations to the rescue… You may not be able to use Migrations from the Package Manager Console because the logic to discover your model may require you full application to be running. Fortunately those commands are just thin wrappers over an API. Here is some code to automatically change the database when new classes or properties are added to the model. My recent blog post has more details on invoking Migrations from code.
var config = new DbMigrationsConfiguration<MyContext> { AutomaticMigrationsEnabled = true }; var migrator = new DbMigrator(config); migrator.Update();



I have a system that needs custom fields per client. I have two approaches:
* XML columns to serialize client extension objects
* Client specific add-on tables using above dynamic model
What does the DbContext look like if it is dynamic? Do you access the dynamic entities using the DbContext.Entities?
Which approach do you suggest?
jarrettv
April 11, 2012
i have a similar approuch with my application. a core module and any pluggable modules with entities and entity-mappings. but my core module doesnt know anything about the comming pluggable modules. how can i uses migration in this scenario without using AutomaticMigrationEnabled = true ? the nuget-console doesnt work in this case and i want to have migrations per module. thank you
Ali Ramezani
June 25, 2012
I was thinking to generate EntityTypeConfiguration dynamically from run time and i don’t want any EF dependency in Models[That is why i avoid Data Annotation].
So I declare a custom attribute(or can be any configuration file later on)
[AttributeUsage(AttributeTargets.Property, AllowMultiple=true )]
public class PersistableMemberAttribute : Attribute
{
public bool Iskey;
public bool IsRequired;
public bool IsIgnored;
public bool IsMany;
public string HasForeignKey;
public bool PropertyIsRequired;
public bool PropertyIsOptional;
}
And here is one of my Models is look like:
public class Blog
{
[PersistableMember(Iskey=true)]
public Guid BlogId { get; set; }
[PersistableMember(PropertyIsRequired = true)]
public string Name { get; set; }
public string Url { get; set; }
[PersistableMember(IsIgnored=true)]
public int Rating { get; set; }
[PersistableMember(IsMany =true)]
public ICollection Posts { get; set; }
}
Now I am going to write a generic EntityTypeConfiguration , which will create the configuration dynamically on run time based on the attribute values
public class GenericEntityConfiguration : EntityTypeConfiguration where T : class
{
public GenericEntityConfiguration()
{
var members = typeof(T).GetProperties();
if (null != members)
{
foreach (var property in members)
{
var attrb= property.GetCustomAttributes(typeof( PersistableMemberAttribute ),false).OfType();
if (attrb != null && attrb.Count() > 0)
{
foreach (var memberAttributute in attrb)
{
if (memberAttributute.Iskey || memberAttributute.IsIgnored)
{
var entityMethod = this.GetType().GetMethod(“Setkey”);
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.IsRequired)
{
var entityMethod = this.GetType().GetMethod(“SetRequired”);
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.PropertyIsRequired || memberAttributute.PropertyIsOptional)
{
var entityMethod = this.GetType().GetMethod(“SetPropertyConfiguration”);
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
}
}
}
}
}
public void SetPropertyConfiguration(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.PropertyIsRequired)
{
this.Property((Expression<Func>)lambda).IsRequired();
}
if (attribute.PropertyIsOptional)
{
this.Property((Expression<Func>)lambda).IsOptional();
}
}
public void Setkey(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.Iskey)
{
this.HasKey((Expression<Func>)lambda);
}
if (attribute.IsIgnored)
{
this.Ignore((Expression<Func>)lambda);
}
}
public void SetRequired(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) where TResult : class
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.IsRequired)
{
this.HasRequired((Expression<Func>)lambda);
}
}
}
But i got the compilation error of
Error 1 The type ‘TResult’ must be a non-nullable value type in order to use it as parameter ‘T’ in the generic type or method ‘System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression<System.Func>)’ D:\R&D\UpdateStorePOC\UpdateStorePOC\Data\GenericEntityConfiguration.cs 63 17 UpdateStorePOC
which for :
if (attribute.PropertyIsRequired)
{
this.Property((Expression<Func>)lambda).IsRequired();
}
if (attribute.PropertyIsOptional)
{
this.Property((Expression<Func>)lambda).IsOptional();
}
that means that I need to put a constraint on my method to restrict it to a value type. In C#, this is done with the ‘struct’ keyword.
public void SetPropertyConfiguration(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) Where TResult : struct
But Its not the solution since my property type can be a class e.g string or int, bool double, etc . So it is not at all clear that I can send them into this method. Please help me to solve this issue whether there is any other way to do it. I already posted this in MSDN forum weeks ago , still not getting any response fron anyone: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/cd9df9d1-2b47-4676-9070-58cbb6ae0083
Morshed
November 16, 2012
Another Question I have : I would like to create a Dynamic Code-Based DBMigration ………which will create Table and extended properties on the fly using Reflection (By loading some external assembly of Upgrade version)………..I can compare them and find out the changes of properties and added persitable classes………….But CreateTable Method in DbMigration is asking me for expression ..
protected internal TableBuilder CreateTable(
string name,
Func columnsAction,
Object anonymousArguments
)
……any example to create such Table-Expression on the fly .
morshedanwar
November 16, 2012
Hi, I’m using the EntityConfiguration approach as above together with MEF. I have a core application and modules that export the entities which are discovered and loaded at runtime. Exporting the model classes from the core application works with no problems but exporting them from the respective modules causes the following exception on the “addMethod.MakeGeneric…….” part:
Object of type ‘Forums.Data.Model.ForumConfig’ cannot be converted to type ‘System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1[Forums.Data.Model.Forum]‘.
In this scenarion the Entity is “Forums.Data.Model.Forum” and the configuration class is “Forums.Data.Model.ForumConfig’ : EntityTypeConfiguration”
Will you be able to provide some insight into what’s going on and how to go about to make it work as intended?
Joel
April 23, 2013
Hi,
After model building and db migrations how can I preform actions on entity (read, write, delete, update).
If I adding class Product
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
And trying to read/write/delete/update it I can’t.
using(MyContext _db = new MyContext())
{
_db.Product ???
}
Thanks,
Andrey
Andrey
May 18, 2013
Get it work:
List l = _db.Set().ToList();
Andrey
May 18, 2013
Hi Andrey,
Yes, that’s the correct approach, glad you found it.
~Rowan
romiller.com
May 20, 2013