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
相关产品推荐
相关产品推荐

