linq - 将 LINQ/AutoMapper 项目展平至嵌套子项

标签 linq automapper projection

我已经阅读了很多与这个问题相关的文章,并使用了其中一些问题/答案来接近我的情况的答案,但我不能完全正确。

我有一个包含 5 个表的 EF6 上下文(祖 parent 、祖 parent parent 、 parent 、 parent child 和 child )。 GP 和 PC 表是简单的多对多关系,将家族层次结构联系在一起。

我的业务需求是查询数据库并返回祖 parent 对象的列表,其中包含所有孙子对象的列表,而无需将孙子对象嵌套在父对象下。我有 3 个 ViewModel 类,它们是其对应表的子集,我想将数据库层次结构扁平化为 GrandparentViewModel 类列表,其中 GVM =

public class GrandparentViewModel
{
    public int GrandparentId { get; set; }
    public string Name { get; set; }

    public List<ChildViewModel> Grandchildren { get; set; }
}

还需要注意的是,我在查询中使用 AutoMapper 的 ProjectTo<> 扩展方法,因此我可以卸载投影并仅从每个表中选择字段的子集....即...我的 DateOfBirth 已打开每个表,我不想查询和/或返回该字段。

在尝试实现此功能时,我偶然发现了 AutoMapper 的 ITypeConverter 接口(interface),并构建了一个为祖 parent 和 child 实现该接口(interface)的类。以下是这些类:

public class GrandparentConverter : ITypeConverter<Grandparent, GrandparentViewModel>
{
    public GrandparentViewModel Convert(ResolutionContext context)
    {
        var entities = context.SourceValue as Grandparent;

        return entities
            .Select(x => new GrandparentViewModel
            {
                GrandparentId = x.GrandparentId,
                Name = x.Name,
                Grandchildren = AutoMapper.Mapper.Map<IEnumerable<Parent>, List<ChildViewModel>>(x.Parents)
            }).ToList();

        //return new GrandparentViewModel
        //{
        //    GrandparentId = entities.GrandparentId,
        //    Name = entities.Name,
        //    Grandchildren = entities.Parents.SelectMany(x => x.Children.Select(y => new ChildViewModel
        //    {
        //        ChildId = y.ChildId,
        //        Name = y.Name
        //    }).ToList()).ToList()
        //};
    }
}


public class ChildConverter : ITypeConverter<IEnumerable<Parent>, List<ChildViewModel>>
{
    public List<ChildViewModel> Convert(ResolutionContext context)
    {
        var entities = context.SourceValue as IEnumerable<Parent>;

        return entities
            .SelectMany(x => x.Children)
            .Select(x => new ChildViewModel
            {
                ChildId = x.ChildId,
                Name = x.Name
            }).ToList();
    }
}

这是使用代码:

MapperConfiguration mapper = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Child, ChildViewModel>();
            cfg.CreateMap<IEnumerable<Parent>, List<ChildViewModel>>().ConvertUsing<ChildConverter>();

            cfg.CreateMap<Grandparent, GrandparentViewModel>();
            cfg.CreateMap<IEnumerable<Grandparent>, List<GrandparentViewModel>>().ConvertUsing<GrandparentConverter>();
        });

        FamilyEntities db = new FamilyEntities();
        List<GrandparentViewModel> entities = db.Set<Grandparent>()
            .Where(x => x.GrandparentId == 1)
            .ProjectTo<GrandparentViewModel>(mapper)
            .ToList();

目前,该解决方案按照我的预期构建、运行并返回一个单一的 GrandparentViewModel 类,但所有字段(包括祖 parent ...即...名称上的字段)均为空。

关于我缺少什么和/或为什么数据没有被填充有什么想法吗?我尝试在该 TypeConverter 类中设置断点,但它永远不会执行,即使 AutoMapper 的 MapperConfiguration 类中指定的唯一映射配置正在使用该转换器。如果我删除该 CreateMap 调用,AutoMapper 就会抛出“缺少配置”错误。

非常感谢任何建议。

编辑:我构建了此问题的缩小版本,当我不构建 AutoMapper MapperConfiguration 并将其传递给 ProjectTo 方法时,会命中自定义 TypeConverter 类中的断点。因此,在我原来的帖子中,问题似乎是 AutoMapper 实际上并未使用 ConvertUsing 方法中指定的转换器。

最佳答案

确认这是 AutoMapper 的 ProjectTo 逻辑中的错误。 Issue 1216已使用 AutoMapper 记录以纠正此问题。与此同时,我得到了一个似乎有效的解决方法。

cfg.CreateMap<Grandparent, GrandparentViewModel>()
   .ForMember(d => d.Grandchildren, 
       opt.MapFrom(s => s.Parents.SelectMany(x => x.Children));

关于linq - 将 LINQ/AutoMapper 项目展平至嵌套子项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36344338/

相关文章:

asp.net-mvc-2 - "Merge"带或不带 AutoMapper 的模型和 View 模型?

mongodb - Mongo 项目测试值是否在数组中

opengl - 根据视平面计算透视投影矩阵

c# - 如何计算包含多个分隔符的文件中存储的数字的出现次数?

c# - 我可以扩展 LINQ-to-SQL 支持的运算符吗?

c# - 如何将 Linq 扩展方法重写为委托(delegate)?

python - Python 中不同深度的多个 3D 对象的透视投影

c# - LINQ外连接动态OrderBy

c# - NuGet 包管理器 : 'AutoMapper' already has a dependency defined for 'Microsoft.CSharp'

c# - 为什么 AutoMapper 有一个 IValueFormatter,而它有一个看似更强大的 ValueResolver?