AutoMapper Project().To()并对子集合进行排序

本文关键字:排序 子集合 Project To AutoMapper | 更新日期: 2023-09-27 17:59:21

我有一个对象图,我正在使用EF CodeFirst和AutoMapper从数据库加载到DTO:-

public class Foo
{
  public int Id { get; set; }
  public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar
{
  public int Id { get; set; }
  public int FooId { get; set; }
  public virtual Foo Foo { get; set; }
  public string Name { get; set; }
  public int SortOrder { get; set; }
}
public class FooDto
{
  public IEnumerable<BarDto> Bars { get; set; }
}
public class BarDto
{
  public string Name { get; set; }
  public int SortOrder { get; set; }
}

我的映射看起来像:-

mapper.CreateMap<Foo, FooDto>();
mapper.CreateMap<Bar, BarDto>();

到目前为止,一切都很好。我可以很好地从我的上下文和项目中抓取实体到DTO:-

var foos = context.Foos.Project().To<FooDto>();

然而,我不能用这种方法,通过IQueryable中的SortOrderBars进行排序。

如果我尝试:-

mapper.CreateMap<Foo, FooDto>()
  .ForMember(
    x => x.Bars
    opt => opt.MapFrom(src => src.Bars.OrderBy(x => x.SortOrder)));
mapper.CreateMap<Bar, BarDto>();
var foos = context.Foos.Project().To<FooDto>();

我得到一个例外:-

System.InvalidOperationException: Sequence contains no elements
  at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
  at AutoMapper.MappingEngine.CreateMapExpression(Type typeIn, Type typeOut)
  ...

这似乎与https://github.com/AutoMapper/AutoMapper/issues/159-尽管我已经在为子集合使用复杂类型。我猜CreateMapExpression在子集合上不支持OrderBy?

如果我不使用.Project().To(),那么我可以很容易地对子集合进行排序:-

var model = context.Foos.Select(x => new FooDto()
{
  Bars = x.Bars.OrderBy(y => y.SortOrder)
});

但我必须在任何我想使用它的地方重复映射,这违背了使用AutoMapper的目的。

奇怪的是:-

1) 我可以对子集合执行其他(更复杂的?)操作,并将这些操作展平到我的父DTO中,没有问题:-

mapper.CreateMap<Foo, FooDto>()
  .ForMember(
    x => x.AllBarsHaveAName,
    opt => opt.MapFrom(src =>
      src.Bars.All(x => x.Name != null)));

2) 我可以很好地在内存中Mapper.Map<FooDto>(foo);,它会对条进行排序,没有问题。

在使用.Project().to()时,是否可以在IQueryable级别对子集合进行排序

AutoMapper Project().To()并对子集合进行排序

最终修改了AutoMapper源代码以支持此场景。希望提议的修复方案能被接受,但与此同时,你可以在以下网站上看到详细信息:-

https://github.com/AutoMapper/AutoMapper/pull/327

我想知道在映射过程中对Queryable中的Bars进行排序是否是最好的方法?把排序放在地图上不是意味着它在不合适的时间排序吗?

例如,如果您只是想知道Bars集合是否包含1个项目,该怎么办?使命感CCD_ 4仍然会在数据库中产生排序。

也许在FooDTO中有另一个属性(在映射中被忽略)会更好,它看起来像这样:

    public IEnumerable<BarDto> SortedBars
    {
        get
        {
            if (Bars == null)
                return null;
            return Bars.OrderBy(x => x.SortOrder).ToList();
        }
    }