【问题标题】:The model backing the 'EFDbContextProxy' context has changed - Testing cache?支持“EFDbContextProxy”上下文的模型已更改 - 测试缓存?
【发布时间】:2019-03-23 01:20:41
【问题描述】:

我对实体进行了更改,运行了迁移并更新了数据库。 然后我重新运行了一个测试,它抛出了一个错误:

支持“EFDbContextProxy”上下文的模型在创建数据库后发生了变化。考虑使用 Code First 迁移来更新数据库

如果我运行应用程序,我不会收到此错误。看来我的 EFDbContextProxy(不管那是什么)正在使用数据结构的旧缓存。

有什么办法解决这个问题吗?

这就是我在测试中准备数据库上下文的方式:

public class EFFieldViewerRepository_Setup
{
    protected DateTime now;
    protected Mock<EFDbContext> mockDbContext;
    protected EFFieldViewerRepository fieldViewerRepository;
    protected IDbSet<FieldViewer> fieldViewerDbSet;

    public EFFieldViewerRepository_Setup()
    {
        this.now = DateTime.Now;
        this.mockDbContext = new Mock<EFDbContext>() { CallBase = true };
        this.fieldViewerRepository = new EFFieldViewerRepository( this.mockDbContext.Object );
        ...
    }

这是我的堆栈跟踪:http://pastebin.com/kAUmhi3j

【问题讨论】:

  • 您是否在所有实体上尝试了Refresh?你能提供一个堆栈跟踪吗?
  • 我已经添加了测试堆栈跟踪
  • @derape - 我如何执行“刷新”

标签: c# entity-framework


【解决方案1】:

我必须创建一个 MockEFDbContext 并扩展 EFDbContext。在构造内部我运行Database.SetInitializer&lt;EFDbContext&gt;(null):

public class MockEFDbContext : EFDbContext
{
    public MockEFDbContext()
    {
        Database.SetInitializer<EFDbContext>(null);
    }
}

然后我在测试中使用了这个新的MockEFDbContext,而不是普通的:

this.mockDbContext = new Mock<MockEFDbContext>() { CallBase = true };

来源:
- http://gaui.is/how-to-mock-the-datacontext-entity-framework/
- https://msdn.microsoft.com/en-us/library/gg679461(v=vs.113).aspx

【讨论】:

    【解决方案2】:

    LocalDB 数据库可能是罪魁祸首(听起来很奇怪,我知道)

    如果 Entity Framework 配置为生成 LocalDB 数据库,则由 Castle 创建的 Moq 的 DBContext 代理类将反过来创建一个 LocalDB 数据库,该数据库可能与最初创建数据库后添加的 EF 迁移不同步。我发现删除 LocalDB 数据库可以解决问题,尽管可能有更好的解决方案,包括@Jimmyt1988 提供的答案。

    实体框架配置

    我在一个 Visual Studio 测试项目中使用 Moq 运行单元测试,该项目还具有连接到目标数据库的集成测试。因此,我最终在我的 app.config 中有一个这样的节点。

    <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="Oracle.ManagedDataAccess.Client" type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.122.18.3, Culture=neutral, PublicKeyToken=89b483f429c47342" />
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
    

    起订量测试设置

    我的起订量测试设置类似于 @Jimmyt1988 的

    private Mock<DbSet<OutgoingEntry>> _set;
    private Mock<MyContext> _context;
    private ModelService<OutgoingEntry, MyContext> _service;
    
    [NUnit.Framework.SetUp]
    public void Setup()
    {
        _set = new Mock<DbSet<OutgoingEntry>>();
        _set.Reset();
        _context = new Mock<MyContext>();
        _context.Reset();
        _context.Setup(m => m.OutgoingEntries).Returns(_set.Object);
        _context.Setup(m => m.Set<OutgoingEntry>()).Returns(_set.Object);
        _service = new OutgoingService(_context.Object);
    }
    

    神秘的代理类和LocalDB

    在上面的示例中,_context.ObjectCastle.Proxies.MyContextProxy 的一个实例。这是在运行时生成的,以允许 Moq 覆盖方法和属性。但是,如果EF配置如上,代理类的生成仍然会触发数据库初始化。这最终会产生这样的数据库:

    无心破坏,然后笨拙地修复它们

    当我添加新迁移时,以上所有细节对我来说或多或少都是透明的。不幸的是,这导致了原始问题中提到的确切错误。为了解决根本问题,我只是删除了 Moq/Castle 创建的 LocalDB 文件。这比听起来更棘手。我发现这些特定步骤适用于 Windows 10。

    • 以管理员身份打开 Powershell。
    • 调用SqlLocalDB.exe stop mssqllocaldb
    • 现在调用SqlLocalDB.exe delete mssqllocaldb 此命令将有效地删除您拥有的任何 LocalDB 数据库。仅当您不关心 LocalDB mssqllocaldb 实例时才这样做
    • 删除由 Moq / Castle 创建的 mdf 和日志文件。我在我的 Windows 主目录中找到了这些。
    • 在 Visual Studio 的测试运行程序中重新运行测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-30
      • 2013-08-24
      • 2023-03-23
      • 2015-04-29
      • 2012-07-04
      • 1970-01-01
      • 1970-01-01
      • 2014-04-19
      相关资源
      最近更新 更多