带有代码优先的EntityFramework:在运行时检测实体类型

本文关键字:运行时 检测 实体 类型 EntityFramework 代码 | 更新日期: 2023-09-27 18:13:22

当使用代码优先方法的EntityFramework时,您通常从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属性到我的类?

带有代码优先的EntityFramework:在运行时检测实体类型

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

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

传统上,在EF中没有什么可以阻止您这样做,除非您需要迁移。现在EF支持同一数据库上不同DbContexts的迁移