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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:45:35