EF Core 2.1内存数据库未更新记录。

6
我将使用内存数据库提供程序进行集成测试,但似乎无法更新记录。我已经对真实的SQL数据库运行了相同的代码,并成功更新了所有内容。这是我的测试夹具代码。 测试夹具:
public class TestFixture<TStartup> : IDisposable
{
    private readonly TestServer _testServer;
    public HttpClient TestClient { get; }
    public IDatabaseService DbContext { get { return _testServer.Host.Services.GetService<DatabaseService>(); } }

    public TestFixture() : this(Path.Combine("src")) { }

protected TestFixture(string relativeTargetProjectPatentDir)
{
    Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Testing");

    var builder = new WebHostBuilder()
        .ConfigureServices(services =>
        {
            services.AddDbContext<DatabaseService>(options =>
                options.UseInMemoryDatabase("TestDB")
                .EnableSensitiveDataLogging());
        })
        .UseEnvironment("Testing")
        .UseStartup<Startup>();

    _testServer = new TestServer(builder)
    {
        BaseAddress = new Uri("http://localhost:5010")
    };

    TestClient = _testServer.CreateClient();
    TestClient.BaseAddress = _testServer.BaseAddress;
}

    public void Dispose()
    {
        TestClient.Dispose();
        _testServer.Dispose();
    }
}

我花了大部分时间在谷歌上搜索这个问题,但没有找到其他人谈论它,所以我认为这可能是我的问题而不是EF的错误。我相信有人会注意到一个无法更新的数据库。


这个相关的问题也可以帮助:https://dev59.com/QFQJ5IYBdhLWcg3wPTYn - Jess
5个回答

6

使用单例模式可以进行更新,但我使用CQRS架构,为了在端到端测试中检查条目是否已更新,需要重新加载条目。

Context.Entry(entity).Reload();

我希望你能有所收获。

确实帮了我,但我很好奇为什么在某些情况下需要这样做,而在其他情况下似乎可以正常工作? - Saher Ahwal
如果可以的话,我会给你+2分。+1分是因为你帮了我,另外+1分是因为你提到了我正在使用但并不完全正确的CQRS模式。 - Jess
@SaherAhwal 如果您能分享这些案例,那么我可以回复。 - ZeSzymi

4

结果证明,将我的测试夹具中的 DbContext 生命周期更改为单例可以解决我的问题。


我使用了相同的策略,但是我使用了XUnit属性(使我的测试按顺序运行):https://dev59.com/4VoU5IYBdhLWcg3w_alI#55700172 - Jeremy Thompson
谢谢你的回答!这真的让我很困惑。根据你的答案,我在这篇帖子中添加了我所做的更改以使其正常工作。 - JCisar
但 DbContext 不是线程安全的 - 那么这怎么解决问题的呢? - Saher Ahwal

1

补充Chris的回答。这里是一个例子,展示了我遇到的问题和如何解决它:

services.AddDbContext<TestDbContext>(options => {
 options.UseInMemoryDatabase("TestDb");
});

var options = new DbContextOptionsBuilder<TestDbContext>()
                        .UseInMemoryDatabase(databaseName: "TestDb")
                        .Options;
services.AddSingleton(x => new TestDbContext(options));

1

可能是DbContext的使用方式不正确。我曾经遇到过同样的问题。我和你一样使用了DbContext。我只是通过.Host.Services.GetService<TContext>返回实例。这种方法的问题在于,DbContext永远不会释放已跟踪的实体,因此您要么将实体的State设置为EntityState.Detached并强制DbContext重新加载它,要么使用作用域。

using (var scope = _testServer.Host.Services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
  var dbContext = scope.ServiceProvider.GetRequiredService<DatabaseService>();
  //make any operations on dbContext only in scope
}

1

使用 AsNoTracking 行为可能会在以下情况下起到额外的作用,

services.AddDbContext<TestDbContext>(
            a => a.UseInMemoryDatabase(databaseName: "TestDb").UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking),
            ServiceLifetime.Singleton)

另外,你是如何更新记录的?这似乎在EFCore InMemory中进行跟踪。

_dbContext.Entry(modifyItem).State = EntityState.Modified;
            

然而,这似乎并不起作用。

_dbContext.Entry(existingItem).CurrentValues.SetValues(modifyItem);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接