让我们说,理论上,我有一个数据库数量未知的数据库,名称如下:
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()
,如果是这样,这是一个好主意吗?有更优雅的方式吗?
答案 0 :(得分:1)
我不知道数据库中有多少这些表。
因此单个上下文不可能,特别是不能使用代码。 EDMX支持这种情况(但EDMX设计器不支持),但前提是您能够在设计时定义所有表。它被称为MEST。
然而,发生的情况是上下文中的OnModelCreating()仅在第一个实例化时被调用一次,因此该表始终映射到MyTable1。
是的,这正是发生的事情。模型创建只执行一次,因为它是非常昂贵的操作,并且模型在整个应用程序生命周期中重复使用。
有更优雅的方式吗?
有一种方法,但它远离优雅:
DbModel
实例DbModel
实例上调用编译以获取DbCompiledModel
(缓存此内容)DbCompiledModel
实例传递给DbContext
构造函数优雅的方法是不使用该方法,而是使用context.Database.SqlQuery
来执行您的动态查询并返回您的类型的实例 - 如果查询返回与您的类型中的属性具有相同名称的列,EF将处理它甚至没有映射,但它将是只读解决方案。