我有一个对象图,我正在使用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>();
然而,我不能用这种方法做的是Bars
在IQueryable中SortOrder
排序。
如果我尝试: -
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);
就好了,它会对条形排序没问题。
可以在IQueryable级别对子集合进行排序,同时仍然使用.Project()。To()?
答案 0 :(得分:13)
完成修改AutoMapper源代码以支持此方案。希望提议的修复程序将被接受,但在此期间您可以在以下位置查看详细信息: -
答案 1 :(得分:0)
我想知道在映射期间对Queryable中的Bars进行排序是最好的地方吗?不会在地图中放置排序意味着它在不适当的时间排序?
例如,如果您只是想知道Bars集合是否包含1个项目怎么办?调用
FooDto.Bars.Any()
仍会导致数据库中的排序。
也许最好在FooDTO中使用另一个属性(在映射中忽略),如下所示:
public IEnumerable<BarDto> SortedBars
{
get
{
if (Bars == null)
return null;
return Bars.OrderBy(x => x.SortOrder).ToList();
}
}