EF测试中InMemoryDatabase无法关联实体关系,结果不符预期
问题:InMemoryDatabase中Include关联失效导致测试返回0条数据
测试预期返回3条Entry数据,但实际结果为0。生产环境该功能正常,但在InMemoryDatabase中,Get方法的.Include(n => n.Task.ApplicationUser)语句无法正确关联Entry与Task,调试时Autos窗口显示两者已关联,推测是内存数据库配置或查询逻辑存在问题。
Get方法代码
public IEnumerable<Entry> Get(string userId, DateTime from, DateTime to) { List<Entry> result; try { result = _db.Entries .Include(n => n.Task.ApplicationUser) //InMemoryDb无法在此关联Task与Entries .Where(n => n.Task.ApplicationUserId == userId).Select(n => n) .Where(n => (n.Created.Date >= from.Date) && (n.Created.Date <= to.Date)) .ToList(); } catch (Exception e) { _logger.LogError($"Exception: {e.Message} StackTrace: {e.StackTrace}"); return new List<Entry>(); } return result; };
内存数据库配置代码
private async Task<TasksContext> GetDbContext() { var options = new DbContextOptionsBuilder<TasksContext>() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) .Options; // 创建模拟的DBcontext var dbContext = new TasksContext(options); dbContext.Database.EnsureDeleted(); dbContext.Entries.AsNoTracking(); dbContext.Tasks.Add(new Task { Id = 1, Name = "RunningId1", GroupId = 4, Created = _createdFirstEntry, ApplicationUserId = _userId }); dbContext.Tasks.Add(new Task { Id = 2, Name = "CookingId2", GroupId = 4, Created = _createdSecondEntry, ApplicationUserId = _userId }); dbContext.Tasks.Add(new Task { Id = 3, Name = "ReadingId3", GroupId = 4, Created = _createdThirdEntry, ApplicationUserId = _userId }); dbContext.Entries.Add(new Entry { Id = _entryId_1, TaskId = _taskId_1, Duration = _duration, Created = _createdFirstEntry, LastUpdated = null, Deleted = null }); dbContext.Entries.Add(new Entry { Id = _entryId_2, TaskId = _taskId_2, Duration = _duration, Created = _createdSecondEntry, LastUpdated = null, Deleted = null }); dbContext.Entries.Add(new Entry { Id = _entryId_3, TaskId = _taskId_3, Duration = _duration, Created = _createdThirdEntry, LastUpdated = null, Deleted = null }); await dbContext.SaveChangesAsync(); return dbContext; }
测试方法代码
public async void Get_TakesValidUserIdAndDateRange_ReturnsListWithThreeElements() { // Arrange var dbContext = await GetDbContext(); var entryRepository = new EntryRepository(dbContext, _logger, _mapper); // Act var result = entryRepository.Get(_userId,_createdFirstEntry, _createdThirdEntry); // Assert result.Should().BeOfType(typeof(List<Entry>)); result.Count().Should().Be(3); }
解决方法
1. 移除无效的AsNoTracking()调用
dbContext.Entries.AsNoTracking()仅创建了一个无跟踪查询,并未对后续的实体添加操作生效,反而可能干扰实体关联,直接删除该行代码。
2. 确保外键值完全匹配
检查_taskId_1、_taskId_2、_taskId_3的取值是否分别为1、2、3(与Tasks的Id对应)。InMemoryDatabase不会自动关联外键,必须手动保证Entry的TaskId与Task的Id完全一致。
3. 调整查询逻辑顺序
先筛选Entry的日期范围,再进行关联查询,避免过早依赖未加载的关联实体,同时使用ThenInclude明确嵌套关联:
result = _db.Entries .Where(n => n.Created.Date >= from.Date && n.Created.Date <= to.Date) .Include(n => n.Task) .ThenInclude(t => t.ApplicationUser) .Where(n => n.Task.ApplicationUserId == userId) .ToList();
4. 修复测试方法的异步签名
async void会导致测试框架无法等待异步操作完成,将测试方法改为async Task:
public async Task Get_TakesValidUserIdAndDateRange_ReturnsListWithThreeElements() { // Arrange var dbContext = await GetDbContext(); var entryRepository = new EntryRepository(dbContext, _logger, _mapper); // Act var result = entryRepository.Get(_userId,_createdFirstEntry, _createdThirdEntry); // Assert result.Should().BeOfType(typeof(List<Entry>)); result.Count().Should().Be(3); }
内容的提问来源于stack exchange,提问作者Lucas Adams
相关产品推荐
相关产品推荐

