0

假设,理论上,我有一个包含未知数量表的数据库,命名如下:

MyTable1
MyTable2
MyTable3
..

等等。这些表中的每一个都具有完全相同的架构。我不知道数据库中有多少这样的表。

使用 EF5.0 和代码优先,我希望能够通过传入一个参数来通过一个 DbContext 引用这些表中的任何一个:

using (var db = new MyContext())
{
    db.GetMyTable(2).ForEach(e => Console.WriteLine("Table 2 entry: " + e.MyField));
    db.GetMyTable(5).ForEach(e => Console.WriteLine("Table 5 entry: " + e.MyField));
}

这可能吗?

我想到的另一种方法是创建完全不同的上下文并.ToTable()在映射中提供正确的:

public class MyContext : DbContext
{
    private int _tableNumber;

    static MyContext()
    {
        Database.SetInitializer<MyContext>(null);
    }

    public MyContext(int tableNumber) : base("Name=TheContextName")
    {
        _tableNumber = tableNumber;
    }

    public DbSet<MyTable> MyTableEntries { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        System.Data.Entity.ModelConfiguration.Conventions.
        modelBuilder.Configurations.Add(new MyTableMap(_tableNumber));
    }
}


 public class MyTableMap : EntityTypeConfiguration<MyTable>
 {
    public MyTableMap(int tableNumber)
    {
        // Primary Key
        this.HasKey(t => t.id);

        // Table & Column Mappings
        this.ToTable("MyTable" + tableNumber);
        this.Property(t => t.id).HasColumnName("id");
        this.Property(t => t.n).HasColumnName("MyField");

    }
 }

然后我可以根据我想要处理的表使用单独的上下文进行操作:

Console.WriteLine("Contents of MyTable1:");
using (var db = new MyContext(1))
{
    db.MyTableEntries.ToList().ForEach(n => Console.WriteLine(n.MyField));
}

Console.WriteLine("Contents of MyTable2:");
using (var db = new MyContext(2))
{
    db.MyTableEntries.ToList().ForEach(n => Console.WriteLine(n.MyField));
}

但是,发生的情况是,OnModelCreating()在上下文中仅在第一次实例化时被调用一次,因此该表始终映射到 MyTable1。是否有某种可以关闭的缓存,以便OnModelCreating()每次都调用它,如果是这样,这是个好主意吗?有没有更优雅的方式来做到这一点?

4

1 回答 1

1

我不知道数据库中有多少这样的表。

因此,单一上下文是不可能的,尤其是代码优先。EDMX 支持这种情况(但 EDMX 设计器不支持),但前提是您能够在设计时定义所有表。它被称为MEST

但是,发生的情况是上下文中的 OnModelCreating() 仅在第一次实例化时被调用一次,因此该表始终映射到 MyTable1。

是的,这正是发生的事情。模型创建只执行一次,因为它是非常昂贵的操作,并且模型在整个应用程序生命周期中被重用。

有没有更优雅的方式来做到这一点?

有一种方法,但它离优雅还很远:

  • 手动创建 DbModelBuilder` 的实例并用您需要的所有映射填充它
  • 在该实例上调用 Build 以获取DbModel实例
  • 在实例上调用编译DbModel以获取DbCompiledModel(缓存此)
  • 现在将DbCompiledModel实例传递给DbContext构造函数

优雅的方法不是使用该方法,而是使用该方法context.Database.SqlQuery执行动态查询并返回类型的实例 - 如果查询返回与类型中的属性同名的列,即使没有映射,EF 也会处理它,但它将是只读解决方案。

于 2012-09-08T21:46:31.700 回答