【问题标题】:AutoMapper -- inheritance mapping not working, same source, multiple destinationsAutoMapper - 继承映射不​​起作用,相同的源,多个目的地
【发布时间】:2012-12-09 06:23:41
【问题描述】:

我可以在 AutoMapper (v2.2) 中为具有相同 Source 类型但不同 Destination 类型的地图使用继承映射吗?

我有这个基本情况(真正的类有更多的属性):

public abstract class BaseViewModel
{
    public int CommonProperty { get; set;}
}

public class ViewModelA : BaseViewModel
{
    public int PropertyA { get; set; }
}

public class ViewModelB : BaseViewModel
{
    public int PropertyB { get; set; }
}

ViewModelAViewModelB是同一个Entity类的不同表示:

public class Entity
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }
    public int Property3 { get; set; }
}

我想为每个 ViewModel 重用 BaseViewModel 的相同映射,例如:

Mapper.CreateMap<Entity, BaseViewModel>()
    .Include<Entity, ViewModelA>()
    .Include<Entity, ViewModelB>()
    .ForMember(x => x.CommonProperty, y => y.MapFrom(z => z.Property1));

Mapper.CreateMap<Entity, ViewModelA>()
    .ForMember(x => x.PropertyA, y => y.MapFrom(z => z.Property2));

Mapper.CreateMap<Entity, ViewModelB>()
    .ForMember(x => x.PropertyB, y => y.MapFrom(z => z.Property3));

但不幸的是,这似乎不起作用。像这样的调用:

var model = Mapper.Map<Entity, ViewModelA>(entity);

导致model 映射了PropertyA,但没有映射CommonProperty。我相信我正确地遵循了https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance 中的示例,但我担心使用相同的 Source 类型创建多个地图会使 AutoMapper 出错。

有什么见解吗?我喜欢将基类映射分组在一起的想法,但这似乎不起作用。

【问题讨论】:

  • 对于这个问题的未来读者 - AutoMapper 似乎已经解决了这个问题。
  • 我正在尝试在这里做同样的事情,但我正在尝试做:var model = Mapper.Map&lt;Entity, BaseViewModel&gt;(entity) 但它返回的是 ViewModelA 的实例,而不是 BaseViewModel 的实例,即使我在说Map 函数返回一个 BaseViewModel 类型。我正在使用 Automapper 3.0,看来 2.2 的原始错误已得到解决。
  • 这篇 SO 帖子帮助我解决了我的问题,并获得了预期的效果。 stackoverflow.com/questions/27317719/…

标签: c# inheritance automapper automapper-2


【解决方案1】:

不幸的是,在这种情况下,AutoMapper 似乎只为每个源类型注册了一个子类映射,即最后一个 (ViewModelB)。这可能是为处理并行层次结构而设计的,而不是用于单一源类型。

要解决这个问题,您可以将常用映射封装在扩展方法中:

public static IMappingExpression<Entity, TDestination> MapBaseViewModel<TDestination>(this IMappingExpression<Entity, TDestination> map)
  where TDestination : BaseViewModel { 
  return map.ForMember(x => x.CommonProperty, y => y.MapFrom(z => z.Property1));
}

并在各个子类映射中使用它:

Mapper.CreateMap<Entity, ViewModelA>()
  .MapBaseViewModel<ViewModelA>()
  .ForMember(x => x.PropertyA, y => y.MapFrom(z => z.Property2));

Mapper.CreateMap<Entity, ViewModelB>()
  .MapBaseViewModel<ViewModelB>()
  .ForMember(x => x.PropertyB, y => y.MapFrom(z => z.Property3));

【讨论】:

【解决方案2】:

你可以在这里做

            CreateMap<Entity, ViewModelA>()
            .InheritMapping(x =>
            {
                x.IncludeDestinationBase<BaseViewModel>();
            });

有扩展代码

public static class MapExtensions
{        

    public static void InheritMapping<TSource, TDestination>(
        this IMappingExpression<TSource, TDestination> mappingExpression,
        Action<InheritMappingExpresssion<TSource, TDestination>> action)
    {
        InheritMappingExpresssion<TSource, TDestination> x =
            new InheritMappingExpresssion<TSource, TDestination>(mappingExpression);
        action(x);
        x.ConditionsForAll();
    }

    private static bool NotAlreadyMapped(Type sourceType, Type desitnationType, ResolutionContext r, Type typeSourceCurrent, Type typeDestCurrent)
    {
        var result = !r.IsSourceValueNull &&
               Mapper.FindTypeMapFor(sourceType, desitnationType).GetPropertyMaps().Where(
                   m => m.DestinationProperty.Name.Equals(r.MemberName)).Select(y => !y.IsMapped()
                   ).All(b => b);
        return result;
    }
    public class InheritMappingExpresssion<TSource, TDestination>
    {
        private readonly IMappingExpression<TSource, TDestination> _sourcExpression;
        public InheritMappingExpresssion(IMappingExpression<TSource, TDestination> sourcExpression)
        {
            _sourcExpression = sourcExpression;
        }
        public void IncludeSourceBase<TSourceBase>(
            bool ovverideExist = false)
        {
            Type sourceType = typeof (TSourceBase);
            Type destinationType = typeof (TDestination);
            if (!sourceType.IsAssignableFrom(typeof (TSource))) throw new NotSupportedException();
            Result(sourceType, destinationType);
        }
        public void IncludeDestinationBase<TDestinationBase>()
        {
            Type sourceType = typeof (TSource);
            Type destinationType = typeof (TDestinationBase);
            if (!destinationType.IsAssignableFrom(typeof (TDestination))) throw new NotSupportedException();
            Result(sourceType, destinationType);
        }
        public void IncludeBothBases<TSourceBase, TDestinatioBase>()
        {
            Type sourceType = typeof (TSourceBase);
            Type destinationType = typeof (TDestinatioBase);
            if (!sourceType.IsAssignableFrom(typeof (TSource))) throw new NotSupportedException();
            if (!destinationType.IsAssignableFrom(typeof (TDestination))) throw new NotSupportedException();
            Result(sourceType, destinationType);
        }
        internal void ConditionsForAll()
        {
            _sourcExpression.ForAllMembers(x => x.Condition(r => _conditions.All(c => c(r))));//указываем что все кондишены истинны
        }
        private List<Func<ResolutionContext, bool>> _conditions = new List<Func<ResolutionContext, bool>>();
        private void Result(Type typeSource, Type typeDest)
        {
                _sourcExpression.BeforeMap((x, y) =>
                {
                    Mapper.Map(x, y, typeSource, typeDest);
                });
                _conditions.Add((r) => NotAlreadyMapped(typeSource, typeDest, r, typeof (TSource), typeof (TDestination)));
        }
    }

}

【讨论】:

    猜你喜欢
    • 2015-12-08
    • 2017-03-13
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多