使用Code First的EntityFramework:在运行时检测实体类型

时间:2015-09-19 09:59:39

标签: c# .net entity-framework

将EntityFramework与Code First方法一起使用时,通常从DbContext派生并为您拥有的所有实体类型创建DbSet属性。

我无法做到这一点,因为我的软件可以与提供编译时未知的新实体类型的模块一起使用。

所以我想在运行时确定可用的实体类型列表。

我部分使用了这段代码:

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[] { });
            }
        }
    }
}

然而,当我这样做时,永远不会调用OnModelCreating。我必须在我的班级添加一个DbSet。我甚至不能将DbSet设为私有或内部,它必须是公共的,这使得它成为一个丑陋的解决方法:

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();
}

添加此变通方法时,我可以通过调用DbContext.Set<EntityType>()方法访问DbSets,因此一切都按预期工作。

问题:有没有办法在不向我的类添加公共DbSet属性的情况下实现相同的功能?

1 个答案:

答案 0 :(得分:1)

你能不能以更加静态的方式解决问题?例如,每个库也可以提供自己的DbContext实现。如果库静态地不知道彼此,那么它们没有静态的方法来为其他库中的类提供导航属性。然后,您可以拥有独立的DbContexts,每个库一个。如何在主代码中使用它们?这取决于你的实现,但我想你可以搞清楚。

当库互相引用时,没有循环,因此,它们形成逻辑拓扑排序。例如,如果库A和B引用C,则A和B中可以有DbContexts而C中不能有DbContexts ,如果它不使用自己的实体。

传统上,除非您需要迁移,否则没有任何东西可以阻止您在EF中执行此操作。现在,对同一数据库中的不同{{1}}进行EF supports迁移。