繁体   English   中英

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

[英]Entity Framework Code First returning same data for different tables mapped to same class

我有一个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);
    }
}

但是,当我传入两个不同的表名时,它们将返回相同的数据。 prevTimers包含完全相同的数据currTimers 如何从每个表中获取唯一数据? 为什么要为两个不同的表获得相同的数据?

var currTimers = new TimerContext(currentTimerTableName).Timers.ToList();
var prevTimers = new TimerContext(previousTimerTableName).Timers.ToList();

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

综上所述,可以深入研究内存模型(您必须使用旧的上下文类型ObjectContext vs. DbContext)。 使用此处的 Rowan Miller的一些代码,您可以找到将哪个表映射到每个实体集。 使用此代码,表变量中的每个项目都有一个包含数据库表名称的读/写表属性。 我没有尝试设置此设置,但似乎确实可行。 当然,您需要在OnModelCreating方法之外的其他地方(例如在构造函数中)更改模型,以便每次创建上下文实例时都将触发代码。

*更新*

因为我一直对学习新事物很感兴趣,所以我不能不去管它,而把一个测试应用程序放在一起。 不幸的是,您似乎无法设置该属性(尽管它是一个读/写属性),因为它引发了一个InvalidOperationException异常,指出该项目是只读的。 也许还有另一种方法,但是我还没有找到……。

*更新*

实际上,该解决方案比我最初提到的要简单得多。 DbContext类的几个构造函数接受DbCompiledModel类的实例作为其参数之一。 使用DbModelBuilder类,您可以构建与通常放在OnModelCreating方法中相同的代码。 您可以调用此类的Build方法来创建DbModel类的实例。 您可以调用此类的Compile方法来创建DbCompiledModel类的实例。 唯一真正的窍门是Build方法需要一些其他信息(我使用了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);

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

无法添加评论,但我只想添加发生在我身上的一件事

我的代码是这样的:

DbModelBuilder builder = new DbModelBuilder();
this.OnModelCreating(builder);
var model = builder.Build(this.Database.Connection);

我以为,当我将当前的DbConnection对象传递给此方法时,它将以某种方式“继承”所有连接设置,但似乎我错了。 经过一段时间的调试,我才意识到它会为我生成一些奇怪的连接字符串,这总是导致找不到数据库问题。 所以我的解决方案是,当实例化“ TestContext”(如Jason Richmeier的答案 )时,将nameOrConnectionString作为第一个参数,将编译后的模型作为第二个参数,就解决了我的问题。

我想知道,由于EF保留了某个模型的内存副本,是否手动创建另一个会在内存中创建一个新副本? 如果我的代码需要多次执行此操作,它将继续在内存中创建新模型,最后以内存溢出结束吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM