EF 手动/动态表注册

问题描述

我正在尝试手动创建一些表并动态映射到 DbSet 但它不起作用。这是我的 DbContext 课:

public abstract class DynamicDbContext : DbContext
{
    private List<IQueryable> m_dbSets;

    public DynamicDbContext([NotNull] DbContextOptions options) :
        base(options)
    {
    }

    public DbSet<T> GetTbl<T>() where T : class
    {
        if (m_dbSets == null)
        {
            m_dbSets = new List<IQueryable>();

            foreach (var iter in GetDynTypes())
            {
                var setMethod = typeof(DbContext).getmethod(nameof(DbContext.Set),new[] { typeof(string) });
                IQueryable foundSet = (IQueryable)setMethod
                    .MakeGenericmethod(iter)
                    .Invoke(this,new object[] { iter.Name });

                    m_dbSets.Add(foundSet);
                }
            }
        }

        return m_dbSets.FirstOrDefault(obj => obj.ElementType == typeof(T)) as DbSet<T>;
    }
    
    protected abstract List<Type> GetDynTypes();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        foreach (var iter in GetDynTypes())
        {
            EntityTypeBuilder builder = modelBuilder.Entity(iter);
            builder.ToTable(iter.Name);
        }
    }
    #endregion
}

该类从应用程序的派生类中获取动态类型,并将这些类作为表注册数据库中。然后我想使用 Linq 来处理这些表,所以我引入了 GetTbl 方法,它会返回 DbSet<T> 以便应用程序可以在这个集合上调用 Linq。这个方法使用反射来获取DbSet,不过我也试过直接调用Set<T>(typeof(T).Name)

当我尝试访问返回的 DbSet 时,结果是异常: 无法为“Abc”创建 DbSet,因为此类型未包含在上下文的模型中

看起来表格已创建,例如当我运行迁移命令时,我可以看到数据库中的表:

dotnet ef migrations add InitialCreate

问题可能出在表映射到 DbSet - 在我的 GetTbl 方法中。或者我可能需要在 OnModelCreating 方法中做一些额外的事情。

不知道是什么问题。任何帮助表示赞赏:-) 谢谢

解决方法

一旦您在 OnModelCreating 中注册了类型,您就可以简单地获得 DbSet

 myDbContext.Set<T>();

因此,更简单的设计是只使用您在运行时专门用于动态实体类型的单个泛型类型。例如

public class DynamicDbContext<T> : DbContext where T:class
{
    public DynamicDbContext([NotNull] DbContextOptions options) :
        base(options)
    {
    }

    public DbSet<T> Entities => this.Set<T>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<T>().ToTable(typeof(T).Name);
        base.OnModelCreating(modelBuilder);
    }
}

当然,如果表不存在,这不会创建表。