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

如何用AutoMapper的IQueryable.ProjectTo实现字典<A,B>到<A,C>的投影?

如何让AutoMapper的ProjectTo支持字典类型投影

问题背景

需要将IDictionary<Guid, From>映射到Dictionary<Guid, To>:

  • 使用IMapper.Map可以正常工作
  • 使用IQueryable.ProjectTo时提示缺少字典类型映射
  • 添加CreateMap<IDictionary<Guid, From>, IDictionary<Guid, To>>()后,所有测试因字典索引器参数错误失败
  • 手动通过ToDictionary实现的投影可以正常运行

原始测试代码

using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Xunit;

public class AutoMapperTests
{
    private readonly IMapper mapper = new MapperConfiguration(
        (cfg) =>
        {
            cfg.CreateMap<From, To>();
        }
    ).CreateMapper();

    [Fact]
    public void AutoMapperConfigurationIsValid() =>
        mapper.ConfigurationProvider.AssertConfigurationIsValid();

    [Fact]
    public void CanMapFromDictToDict()
    {
        var key = Guid.NewGuid();
        var fromDict = CreateFromDict(key, key.ToString());

        var toDict = new[] { fromDict }
            .AsEnumerable()
            .Select(it => mapper.Map<IDictionary<Guid, To>>(fromDict))
            .Single();

        Assert.Single(toDict);
        Assert.True(toDict.ContainsKey(key));
        Assert.Equal(key.ToString(), toDict[key].Id);
    }

    [Fact]
    public void CanProjectFromDictToDict()
    {
        var key = Guid.NewGuid();
        var fromDict = CreateFromDict(key, key.ToString());

        var toDict = new[] { fromDict }
            .AsQueryable()
            .ProjectTo<IDictionary<Guid, To>>(mapper.ConfigurationProvider)
            .Single();

        Assert.Single(toDict);
        Assert.True(toDict.ContainsKey(key));
        Assert.Equal(key.ToString(), toDict[key].Id);
    }

    private IDictionary<Guid, From> CreateFromDict(Guid key, string id) =>
        new Dictionary<Guid, From>
        {
            { key, new() { Id = id } }
        };

    public class From
    {
        public required string Id { get; set; }
    }

    public class To
    {
        public required string Id { get; set; }
    }
}

首次错误信息

System.InvalidOperationException : Missing map from System.Collections.Generic.IDictionary2[System.Guid,AutoMapperTests+From] to System.Collections.Generic.IDictionary2[System.Guid,AutoMapperTests+To]. Create using CreateMap<IDictionary2, IDictionary2>.

添加字典映射后的错误信息

System.ArgumentException : Incorrect number of arguments supplied for call to method 'To get_Item(System.Guid)' (Parameter 'property')

解决方案

AutoMapper无法自动处理字典类型的投影表达式构建,需要为字典映射手动指定转换逻辑,同时兼容内存映射和ProjectTo两种场景:

private readonly IMapper mapper = new MapperConfiguration(
    (cfg) =>
    {
        cfg.CreateMap<From, To>();
        
        // 为字典类型自定义映射逻辑
        cfg.CreateMap<IDictionary<Guid, From>, IDictionary<Guid, To>>()
            // 处理ProjectTo的投影表达式
            .ProjectUsing(src => src.ToDictionary(kvp => kvp.Key, kvp => mapper.Map<To>(kvp.Value)))
            // 处理内存中的Map方法
            .ConvertUsing((src, dest, ctx) => src.ToDictionary(kvp => kvp.Key, kvp => ctx.Mapper.Map<To>(kvp.Value)));
    }
).CreateMapper();

关键说明

  • ProjectUsing:为ProjectTo提供LINQ表达式树,明确告知AutoMapper如何将源字典投影为目标字典
  • ConvertUsing:为内存中的Map方法提供转换逻辑,保持原有功能正常运行
  • 两种逻辑都基于已配置的From到To的映射,无需重复定义字段映射规则

修改后所有测试均可通过,包括配置验证、内存映射和ProjectTo投影测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:24:50