C# 实体框架代码首先返回映射到同一类的不同表的相同数据

C# 实体框架代码首先返回映射到同一类的不同表的相同数据,c#,C#,我有一个类Timer,我想与具有相同结构的不同表一起使用,因此我要传入表名 public class TimerContext : DbContext { public DbSet<Timer> Timers { get; set; } private readonly string _tableName; public TimerContext(string tableName) : base("name=fooDb") { _t

我有一个类
Timer
,我想与具有相同结构的不同表一起使用,因此我要传入表名

public class TimerContext : DbContext
{
    public DbSet<Timer> Timers { get; set; }

    private readonly string _tableName;

    public TimerContext(string tableName) : base("name=fooDb")
    {
        _tableName = tableName;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Timer>().ToTable(_tableName);

        base.OnModelCreating(modelBuilder);
    }
}

EF将在需要时调用OnModelCreating方法来创建模型的内存中副本。完成此操作后,将使用此副本。在您的例子中,生成prevTimers的代码使用映射到当前timers表的内存中模型。如果在OnModelCreating方法上放置一个断点,您应该看到它只被调用一次

综上所述,可以深入挖掘和询问内存中的模型(必须使用老式的上下文类型,ObjectContext vs.DbContext)。使用Rowan Miller的一些代码,您可以找到映射到每个实体集的表。使用此代码,tables变量中的每个项都有一个包含数据库表名的读/写表属性。我还没有试着设置这个,但它看起来确实是合理的。当然,您需要在OnModelCreating方法之外的其他地方修改模型,比如在构造函数中,这样每次创建上下文实例时代码都会触发

*更新*

因为我总是对学习新事物感兴趣,所以我不能把它放在一边,然后编写一个测试应用程序。不幸的是,您似乎无法设置该属性(尽管它是读/写属性),因为它会抛出一个InvalidOperationException,声明该项是只读的。也许还有别的办法,但我还没有找到

*更新*

这个解决方案实际上比我第一次提到的要简单得多。DbContext类的两个构造函数接受DbCompiledModel类的实例作为其参数之一。使用DbModelBuilder类,您可以构建通常放在OnModelCreating方法中的相同代码。您可以调用该类的Build方法来创建DbModel类的实例。您可以调用此类的Compile方法来创建DbCompiledModel类的实例。唯一真正的诀窍是构建方法需要一些额外的信息(我使用了DbProviderInfo类的一个实例,但我认为您也可以使用实际的连接,但这可能会对数据库造成影响)。我已经测试了这个,这个确实可以按预期工作

类似于

DbModelBuilder builder = null;

builder = new DbModelBuilder();
builder.Entity<TestEntity>().ToTable(tableName);

DbModel model1 = null;

model1 = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));

builder.Entity<TestEntity>().ToTable(anotherTableName);

DbModel model2 = null;

model2 = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));

DbCompiledModel compiledModel1 = null;
DbCompiledModel compiledModel2 = null;

compiledMdoel1 = model1.Compile();
compiledMdoel2 = model2.Compile();

TestContext context1 = null;
TestContext context2 = null;

context1 = new TestContext(compiledModel1);
context2 = new TestContext(compiledModel2);
dbmodelbuilderbuilder=null;
builder=newdbmodelbuilder();
builder.Entity().ToTable(tableName);
DbModel model1=null;
model1=builder.Build(新的DbProviderInfo(“System.Data.SqlClient”,“2012”);
builder.Entity().ToTable(另一个表名);
DbModel model2=null;
model2=builder.Build(新的DbProviderInfo(“System.Data.SqlClient”,“2012”);
DbCompiledModel compiledModel1=null;
DbCompiledModel compiledModel2=null;
compiledDoel1=model1.Compile();
compiledDoel2=model2.Compile();
TestContext context1=null;
TestContext context2=null;
context1=新的TestContext(compiledModel1);
context2=新的TestContext(compiledModel2);

当然,TestContext类的构造函数必须将编译后的模型实例传递给基构造函数。

EF将在需要时调用OnModelCreating方法来创建模型的内存副本。完成此操作后,将使用此副本。在您的例子中,生成prevTimers的代码使用映射到当前timers表的内存中模型。如果在OnModelCreating方法上放置一个断点,您应该看到它只被调用一次

综上所述,可以深入挖掘和询问内存中的模型(必须使用老式的上下文类型,ObjectContext vs.DbContext)。使用Rowan Miller的一些代码,您可以找到映射到每个实体集的表。使用此代码,tables变量中的每个项都有一个包含数据库表名的读/写表属性。我还没有试着设置这个,但它看起来确实是合理的。当然,您需要在OnModelCreating方法之外的其他地方修改模型,比如在构造函数中,这样每次创建上下文实例时代码都会触发

*更新*

因为我总是对学习新事物感兴趣,所以我不能把它放在一边,然后编写一个测试应用程序。不幸的是,您似乎无法设置该属性(尽管它是读/写属性),因为它会抛出一个InvalidOperationException,声明该项是只读的。也许还有别的办法,但我还没有找到

*更新*

这个解决方案实际上比我第一次提到的要简单得多。DbContext类的两个构造函数接受DbCompiledModel类的实例作为其参数之一。使用DbModelBuilder类,您可以构建通常放在OnModelCreating方法中的相同代码。您可以调用该类的Build方法来创建DbModel类的实例。您可以调用此类的Compile方法来创建DbCompiledModel类的实例。唯一真正的诀窍是构建方法需要一些额外的信息(我使用了DbProviderInfo类的一个实例,但我认为您也可以使用实际的连接,但这可能会对数据库造成影响)。我已经测试了这个,这个确实可以按预期工作

类似于

DbModelBuilder builder = null;

builder = new DbModelBuilder();
builder.Entity<TestEntity>().ToTable(tableName);

DbModel model1 = null;

model1 = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));

builder.Entity<TestEntity>().ToTable(anotherTableName);

DbModel model2 = null;

model2 = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));

DbCompiledModel compiledModel1 = null;
DbCompiledModel compiledModel2 = null;

compiledMdoel1 = model1.Compile();
compiledMdoel2 = model2.Compile();

TestContext context1 = null;
TestContext context2 = null;

context1 = new TestContext(compiledModel1);
context2 = new TestContext(compiledModel2);
dbmodelbuilderbuilder=null;
builder=newdbmodelbuilder();
builder.Entity().ToTable(tableName);
DbModel model1=null;
model1=builder.Build(新的DbProviderInfo(“System.Data.SqlClient”,“2012”);
builder.Entity().ToTable(另一个表名);
DbModel model2=null;
model2=builder.Build(新的DbProviderInfo(“System.Data.SqlClient”,“2012”);
DbCompiledModel已编译
DbModelBuilder builder = new DbModelBuilder();
this.OnModelCreating(builder);
var model = builder.Build(this.Database.Connection);