You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 6内存数据库测试中SaveChanges()空引用异常问题

EF Core 6.0.16 InMemory数据库SaveChanges触发空引用异常排查与解决

问题场景

使用EF Core 6.0.16的InMemory数据库搭建测试环境时,调用context.SaveChanges()向表中插入数据时抛出空引用异常。通过xUnit Fixture为每个测试类创建独立的数据库提供器,确保测试隔离。

相关代码

FakeDbContextFactory与Fixture实现

public class FakeDbContextFactory : IDbContextFactory<MyContext>
{
    private readonly DbContextOptions<MyContext> _options;

    public FakeDbContextFactory(string name = "FakeTests")
    {
        _options = new DbContextOptionsBuilder<IPSContext>()
            .UseInMemoryDatabase(name)
            .Options;
    }

    public MyContext CreateDbContext()
    {
        return new MyContext(_options);
    }

    public Task<MyContext> CreateDbContextAsync()
    {
        return Task.FromResult(new MyContext(_options));
    }
}

public class MyFixture : IDisposable
{
    public MyFixture()
    {
    }

    public IDbContextFactory<MyContext> CreateFakeDbContext(string databaseName)
    {
        return new FakeDbContextFactory(databaseName);
    }
}

测试类代码

public class HelperTests
{
    private readonly MyFixture  _fixture;
    private readonly IDbContextFactory<MyContext> _fakeDbContextFactory;

    public SignatureHelperTests(MyFixture fixture)
    {
        _fixture = fixture;
        _fakeDbContextFactory = _fixture.CreateFakeDbContext(nameof(HelperTests));
    }

    [Fact]
    public void Test_1()
    {
        // Arrange
        var table = new MyTable
        {
            CreationDateTime = DateTime.Now,
            Id = "1234",
            SignedHash = "HashValue"
        };
    
        using (var context = _fakeDbContextFactory.CreateDbContext())
        {
            context.MyTables.Add(table);
            context.SaveChanges(); // 异常抛出位置
   
            // Act
            var sut = new MyHelper(_fakeDbContextFactory);

            var signature = sut.GetValue("<xml>");

            // Assert
            Assert.Equal(context.MyTables.Single().SignedHash, signature.SignedHash);
        }
    }
}

异常栈信息

System.NullReferenceException : Object reference not set to an instance of an object.

Stack Trace: 
You may need to build and run this test to see links to source files in the stack trace.
lambda_method304(Closure , String )
<>c__DisplayClass4_0`2.<SanitizeConverter>b__1(Object v)
InMemoryTable`1.SnapshotValue(IProperty property, ValueComparer comparer, IUpdateEntry entry)
InMemoryTable`1.Create(IUpdateEntry entry)
InMemoryStore.ExecuteTransaction(IList`1 entries, IDiagnosticsLogger`1 updateLogger)
InMemoryDatabase.SaveChanges(IList`1 entries)
StateManager.SaveChanges(IList`1 entriesToSave)
StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
<>c.<SaveChanges>b__104_0(DbContext _, ValueTuple`2 t)
NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
DbContext.SaveChanges()

排查与解决

从异常栈来看,空引用发生在InMemory数据库的SanitizeConverter相关逻辑中,主要排查方向如下:

1. 修正上下文配置的类型错误

代码中DbContextOptionsBuilder指定的是IPSContext,但实际要创建的是MyContext,类型不匹配会导致EF Core无法正确加载实体配置,这是核心问题:

// 原错误代码
_options = new DbContextOptionsBuilder<IPSContext>()
    .UseInMemoryDatabase(name)
    .Options;
// 修正为
_options = new DbContextOptionsBuilder<MyContext>()
    .UseInMemoryDatabase(name)
    .Options;

2. 检查实体属性配置

  • 排查MyTable实体是否有自定义值转换器,确保转换器逻辑中没有空引用风险;
  • 确认所有映射到数据库的属性都已正确初始化,检查Fluent API或DataAnnotations是否存在配置冲突(比如标记为必填的属性未赋值)。

3. 验证上下文独立性

InMemory数据库按名称隔离,不同上下文实例指向同一名称的内存库,当前测试在同一个using块内操作上下文是合法的,但修正配置后需重新验证数据插入与查询逻辑。

4. 版本兼容性检查

EF Core 6.0.16的InMemory提供器存在少量已知bug,若上述修正无效,可尝试升级到同主版本的最新补丁(如6.0.25),避免版本缺陷导致的异常。

内容的提问来源于stack exchange,提问作者Jimenemex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:23:19