展平 LINQ/AutoMapper ProjectTo 嵌套 children
Flatten LINQ/AutoMapper ProjectTo nested children
我已经查看了很多与此问题相关的 SO 文章,并使用了其中的一些 questions/answers 来接近我的情况的答案,但我不能完全正确。
我有一个包含 5 tables 的 EF6 上下文(Grandparent、GrandparentParent、Parent、ParentChild,和 Child)。 GP 和 PC table 是简单的 many-to-many 关系,将家族等级联系在一起。
我的业务需求是查询数据库和 return grandparent objects 的列表,其中包含他们所有 grandchildren 的列表,但没有 grand children 嵌套在 parent 下。我有 3 个 ViewModel classes,它们是它们对应的 tables 的子集,我想将数据库层次结构扁平化为 GrandparentViewModel classes 的列表,其中 GVM =
public class GrandparentViewModel
{
public int GrandparentId { get; set; }
public string Name { get; set; }
public List<ChildViewModel> Grandchildren { get; set; }
}
同样重要的是要注意,我在查询中使用了 AutoMapper 的 ProjectTo<> 扩展方法,因此我可以卸载投影并且仅 select 每个 table 的字段子集。 ..即...我在每个 table 上都有 DateOfBirth,我不想查询 and/or return 那个字段。
在我试图让它工作的过程中,我偶然发现了 AutoMapper 的 ITypeConverter 接口并构建了一个 class 实现了 grandparent 和 child 的接口。这是那些 classes:
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();
目前,该解决方案构建、运行并 return 一个单一的 GrandparentViewModel class 正如我所期望的,但是所有字段(包括 grandparent...即...名称)为空。
关于我遗漏的任何想法and/or为什么没有填充数据?我尝试在该 TypeConverter class 中设置一个断点,但即使在 AutoMapper 的 MapperConfiguration class 中指定的唯一映射配置正在使用该转换器,它也永远不会执行。如果我删除那个 CreateMap 调用,AutoMapper 就会抛出它的 "Missing configuration" 错误。
非常感谢任何建议。
编辑:我构建了这个问题的缩小版本,当我不构建 AutoMapper MapperConfiguration 并将其传递给 ProjectTo 方法时,自定义 TypeConverter class 中的断点被命中。因此,在我原来的 post 中,问题似乎是 AutoMapper 实际上并未使用 ConvertUsing 方法中指定的转换器。
已确认这是 AutoMapper 的 ProjectTo 逻辑中的错误。 Issue 1216 已使用 AutoMapper 记录以更正此问题。与此同时,我得到了一个似乎有效的解决方法。
cfg.CreateMap<Grandparent, GrandparentViewModel>()
.ForMember(d => d.Grandchildren,
opt.MapFrom(s => s.Parents.SelectMany(x => x.Children));
我已经查看了很多与此问题相关的 SO 文章,并使用了其中的一些 questions/answers 来接近我的情况的答案,但我不能完全正确。
我有一个包含 5 tables 的 EF6 上下文(Grandparent、GrandparentParent、Parent、ParentChild,和 Child)。 GP 和 PC table 是简单的 many-to-many 关系,将家族等级联系在一起。
我的业务需求是查询数据库和 return grandparent objects 的列表,其中包含他们所有 grandchildren 的列表,但没有 grand children 嵌套在 parent 下。我有 3 个 ViewModel classes,它们是它们对应的 tables 的子集,我想将数据库层次结构扁平化为 GrandparentViewModel classes 的列表,其中 GVM =
public class GrandparentViewModel
{
public int GrandparentId { get; set; }
public string Name { get; set; }
public List<ChildViewModel> Grandchildren { get; set; }
}
同样重要的是要注意,我在查询中使用了 AutoMapper 的 ProjectTo<> 扩展方法,因此我可以卸载投影并且仅 select 每个 table 的字段子集。 ..即...我在每个 table 上都有 DateOfBirth,我不想查询 and/or return 那个字段。
在我试图让它工作的过程中,我偶然发现了 AutoMapper 的 ITypeConverter 接口并构建了一个 class 实现了 grandparent 和 child 的接口。这是那些 classes:
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();
目前,该解决方案构建、运行并 return 一个单一的 GrandparentViewModel class 正如我所期望的,但是所有字段(包括 grandparent...即...名称)为空。
关于我遗漏的任何想法and/or为什么没有填充数据?我尝试在该 TypeConverter class 中设置一个断点,但即使在 AutoMapper 的 MapperConfiguration class 中指定的唯一映射配置正在使用该转换器,它也永远不会执行。如果我删除那个 CreateMap 调用,AutoMapper 就会抛出它的 "Missing configuration" 错误。
非常感谢任何建议。
编辑:我构建了这个问题的缩小版本,当我不构建 AutoMapper MapperConfiguration 并将其传递给 ProjectTo 方法时,自定义 TypeConverter class 中的断点被命中。因此,在我原来的 post 中,问题似乎是 AutoMapper 实际上并未使用 ConvertUsing 方法中指定的转换器。
已确认这是 AutoMapper 的 ProjectTo 逻辑中的错误。 Issue 1216 已使用 AutoMapper 记录以更正此问题。与此同时,我得到了一个似乎有效的解决方法。
cfg.CreateMap<Grandparent, GrandparentViewModel>()
.ForMember(d => d.Grandchildren,
opt.MapFrom(s => s.Parents.SelectMany(x => x.Children));