【问题标题】:Flatten LINQ/AutoMapper ProjectTo nested children将 LINQ/AutoMapper 项目展平到嵌套的子项
【发布时间】:2016-03-31 21:40:12
【问题描述】:

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

我有一个 EF6 上下文,其中包含 5 个表(Grandparent、GrandparentParent、Parent、ParentChild 和 Child)。 GP 和 PC 表是简单的多对多关系,将家族层次结构联系在一起。

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

的 GrandparentViewModel 类列表
public class GrandparentViewModel
{
    public int GrandparentId { get; set; }
    public string Name { get; set; }

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

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

在我试图让这个工作正常的过程中,我偶然发现了 AutoMapper 的 ITypeConverter 接口,并构建了一个为祖父母和孩子实现该接口的类。以下是这些类:

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 类,如我所料,但所有字段(包括祖父母...即...名称上的字段)都是空的。

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

非常感谢任何建议。

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

【问题讨论】:

    标签: linq automapper projection


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-15
      • 1970-01-01
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-21
      • 1970-01-01
      相关资源
      最近更新 更多