使用Moq.Dapper模拟QueryAsync多映射时遇splitOn列Id未找到错误
模拟Moq.Dapper多映射QueryAsync时的SplitOn错误及解决方案尝试
尝试使用Moq.Dapper库模拟QueryAsync多映射调用时,出现以下错误:
Multi-map error: splitOn column 'Id' was not found
正常运行的多映射查询代码
var query = $@" SELECT * FROM [{nameof(Dashboard)}] dashboard left join [{nameof(DashboardUser)}] dusers on dashboard.DashboardId = dusers.DashboardId left join [Users] users on dusers.UserId = users.Id WHERE dashboard.{nameof(accountId)} = @{nameof(accountId)} AND dashboard.{nameof(dashboardId)} = @{nameof(dashboardId)}"; Dashboard? dashboardEntity = null; using (var connection = _context.CreateConnection()) { var result = await connection.QueryAsync<Dashboard, DashboardUser, User, Dashboard?>(query, (dashboard, dashboardUser, user) => { if (dashboard == null) return null; if (dashboardEntity == null) { dashboardEntity = dashboard; dashboardEntity.Users = new List<DashboardUser>(); } if (dashboardUser != null) { dashboardEntity.Users.Add(dashboardUser); if (user != null) dashboardUser.User = user; } return dashboardEntity; }, splitOn: $@"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id", param: new { accountId, dashboardId }); }
测试模拟代码及报错
即使在模拟时指定了SplitOn参数,仍触发相同错误:
Func<Dashboard, DashboardUser, User, Dashboard?> funMap = (Dashboard, DashboardUser, User) => Mock.Of<Dashboard>(); public async Task Should_Get_Dashboard() { // Arrange var connection = new Mock<DbConnection>(); IEnumerable<Dashboard> expected = GenFu.ListOf<Dashboard>(1); connection.SetupDapperAsync(c => c.QueryAsync(It.IsAny<string>(), funMap, It.IsAny<object>(), It.IsAny<IDbTransaction>(),It.IsAny<bool>(), "DashboardId,DashboardId,Id", // <-- 已定义SplitOn但仍报错*Multi-map error: splitOn column 'Id' was not found* It.IsAny<int?>(), It.IsAny<CommandType?>())) .ReturnsAsync(expected); _context.Setup(x => x.CreateConnection()).Returns(connection.Object); var dashboardRepository = new DashboardRepository(_context.Object, null, null); CommonResult<Dashboard?> actual = new(); // Act actual = await dashboardRepository.GetDashboard(3, 1); }
是否有解决方案?这是我单元测试代码覆盖率的最后一项任务。
尝试的解决方法及结果
更新1
尝试显式指定泛型参数(代码中TFirst、TSecond、TThird、TResult呈灰色),仍触发相同问题;改用另一种QueryAsync重载后,出现新错误:
System.ArgumentException : 使用多映射API时,如果有非Id的键,请确保设置splitOn参数(参数名: 'splitOn')
尝试用*作为SplitOn参数,无效果。
connection.SetupDapperAsync(c => c.QueryAsync<Dashboard>(It.IsAny<string>(), It.IsAny<Type[]>(), GetFunc, It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<bool>(), $@"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id", It.IsAny<int?>(), It.IsAny<CommandType?>())) .ReturnsAsync(expected);
更新2
定位到问题根源:Dapper内部的MultiMapAsync方法为私有作用域,无法直接对其进行模拟。
更新3
修改Dapper的MultiMapAsync方法为Public后尝试模拟,触发错误:
指定的方法不支持
Func<Dashboard, DashboardUser, User, Dashboard?> funMap = (Dashboard, DashboardUser, User) => Mock.Of<Dashboard>(); private class DontMap { /* hiding constructor */ } public async Task Should_Get_Dashboard() { // Arrange var connection = new Mock<DbConnection>(); IEnumerable<Dashboard> expected = GenFu.ListOf<Dashboard>(1); connection.SetupDapperAsync(c => c.MultiMapAsync<Dashboard, DashboardUser, User, DontMap, DontMap, DontMap, DontMap, Dashboard?>(new CommandDefinition(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<int>(),It.IsAny<CommandType>(), CommandFlags.None, default), funMap, $@"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id")).ReturnsAsync(expected); }
内容的提问来源于stack exchange,提问作者Jeremy Thompson
相关产品推荐
相关产品推荐

