将LINQ / AutoMapper项目展平为嵌套子项

时间:2016-03-31 21:40:13

标签: linq automapper projection

我已经回顾了很多与这个问题相关的SO文章,并使用了一些问题/答案来接近我的情况的答案,但我无法正确理解。

我有一个EF6上下文,有5个表(祖父母,祖父母,父母,父母和孩子)。 GP和PC表是简单的多对多关系,它们将族层次结合在一起。

我的业务要求是查询数据库并返回包含所有孙子列表的祖父对象列表,而不让孙子嵌套在父级之下。我有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&lt;&gt;查询中的扩展方法,所以我可以卸载投影,只从每个表中选择一个字段的子集....即...我在每个表上都有DateOfBirth,我不想查询和/或返回该字段。 / p>

在我努力实现这一目标的过程中,我偶然发现了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会抛出它的&#34; Missing配置&#34;错误。

非常感谢任何建议。

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

1 个答案:

答案 0 :(得分:0)

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

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