AutoMapper Project()。对()和排序子集合

我有一个使用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源代码以支持这种情况。 希望提出的修复方案能够被接受,但在此期间您可以在以下地址查看详细信息: -

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


我想知道在映射期间排序Queryable中的酒吧是否是最好的地方? 不会把这种排序放在地图上意味着它排序在不恰当的时间?

例如,如果您只想知道Bars集合是否包含1个项目? 调用FooDto.Bars.Any()仍然会导致数据库中的排序。

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

    public IEnumerable<BarDto> SortedBars
    {
        get
        {
            if (Bars == null)
                return null;

            return Bars.OrderBy(x => x.SortOrder).ToList();
        }
    }
链接地址: http://www.djcxy.com/p/37411.html

上一篇: AutoMapper Project().To() and sorting a child collection

下一篇: Mapping to an internal type with AutoMapper for Silverlight