简体   繁体   中英

EntityFramework with Code First: Detect entity types at runtime

When using EntityFramework with the Code First approach, you usually derive from DbContext and create DbSet properties for all entity types you have.

I can't do this because my software can be used with modules that provide new entity types that are not known at compile time.

So I would like to determine the list of available entity types at runtime.

I got it partially working with this code:

public class MyDbContext: DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");

        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            // Register all types that derive from ModelBase as entity types
            var entityTypes = assembly
                .GetTypes()
                .Where(t => t.IsSubclassOf(typeof(ModelBase)));

            foreach (var type in entityTypes)
            {
                entityMethod.MakeGenericMethod(type)
                    .Invoke(modelBuilder, new object[] { });
            }
        }
    }
}

However, when I do this, OnModelCreating is never called. I have to add a DbSet to my class. I can not even make the DbSet private or internal, it has to be public, which makes it an ugly workaround:

public DbSet<DummyType> DummyTypes { get; set; }

public MyDbContext(string connectionName):
    base(connectionName)
{
    // Force initialization to make sure OnModelCreating
    // has been called after leaving the constructor
    DummyTypes.Count();
}

When adding this workaround, I can access the DbSets by calling the DbContext.Set<EntityType>() method, so everything works as intended.

Question: Is there a way to achieve the same thing without adding a public DbSet property to my class?

Can't you solve your problem in a more static way? For instance, each library can also provide it own DbContext implementation. If libraries are statically unaware of each other, then there is no static way for them to have navigational properties to classes in other libraries. Then you can have independent DbContexts , one for each library. How to use them in your main code? It depends on your implementation, but I guess you can figure it out.

When libraries reference each other, there can be no loops, so, they form logical topological ordering, For instance if library A And B refer to C, you can have DbContexts in A and B and not in C, if it does not use its own entities.

Traditionally, there was nothing that could prevent you from doing this in EF, unless you needed migrations. Now EF supports migrations for different DbContexts on the same database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM