我已经阅读了很多与这个问题相关的文章,并使用了其中一些问题/答案来接近我的情况的答案,但我不能完全正确。
我有一个包含 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/