Automapper - 忽略基类的属性

时间:2013-05-10 14:21:07

标签: c# .net automapper automapper-2

我在忽略继承自基类的类的属性时遇到了困难。

Mapper.CreateMap<FormViewModelBase, EntityBase>()
.Include<FormViewModel, Entity>()
.ForMember(x => x.Id, o => o.Ignore());

Mapper.CreateMap<FormViewModel, Entity>();

这里唯一要注意的是基类的属性是String,派生类的属性是Int32。

无论如何,当我尝试将FormViewModel的实例映射到Entity时,Entity类的基于String的Id属性始终设置为FormViewModel中的Int值,即使我已指定忽略它。

我在FormViewModel和Entity上使用不同类型的ID的原因是我在Web应用程序中使用RavenDB,并且可以通过字符串或int Id加载对象。在客户端Int Id是首选,因为标准的基于Raven字符串的ID在生成链接时效果不佳。

谁能告诉我这里的问题是什么?

4 个答案:

答案 0 :(得分:1)

所以你的基类看起来像这样吗?

public class FormViewModelBase
{
   public string Id { get; set; }
   // other stuff
}

你的派生类看起来像这样吗?

public class FormViewModel : FormViewModelBase
{
   public new int Id { get; set; }
   // other stuff
}

我假设情况就是这样。

如果是这种情况,则派生的Id将隐藏基本Id属性。

无论如何,您是否正在传递FormViewModel的实际实例并从中制作Entity个对象?

我看到这一行:

Mapper.CreateMap<FormViewModel, Entity>();

对我说“从我发送给你的Entity对象中创建一个新的FormViewModel对象,然后执行默认的常规操作来完成此任务。”

所以当你打电话时:

var anEntity = AutoMapper.Mapper.Map<FormViewModel, Entity>(aFormViewModel);

它将使用Map,而不是基础对象的Map。因为派生的FormViewModel

如果你做了类似的事情:

Mapper.CreateMap<FormViewModel, Entity>()
.ForMember(x => x.Id, o => o.Ignore());

要处理派生对象的映射,我怀疑它会映射到你想要的地图,但是对你想要做的事情了解更多可能会有所帮助。

答案 1 :(得分:0)

您需要在子类的映射中指定映射详细信息(例如忽略某些属性),而不是父项。例如:

Mapper.CreateMap<ParentA, ParentB>
      .Include<ChildA, ChildB>();

Mapper.CreateMap<ChildA, ChildB>
      .ForMember(dest => dest.SomeProperty, opt => opt.Ignore());

您的代码无法正常工作的原因是您在父映射上指定了Ignore()。

答案 2 :(得分:0)

我知道这个问题已经有一年了,但我还没有找到解决这类问题的解决方案。我有同样的问题,经过一些挖掘,我发现的唯一的事情是这种行为没有很好的记录。并且映射基类有效,但忽略它们并不是出于某种原因。

我使用了这种扩展方法,它为我解决了

public static IMappingExpression<TSource, TDestination>
        InheritMappingFromBaseType<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
    {
        var sourceType = typeof(TSource);
        var desctinationType = typeof(TDestination);
        var sourceParentType = sourceType.BaseType;
        var destinationParentType = desctinationType.BaseType;

        expression
            .ForAllMembers(x => x.Condition(r => NotAlreadyMapped(sourceParentType, destinationParentType, r)));

        return expression;
    }

    private static bool NotAlreadyMapped(Type sourceType, Type desitnationType, ResolutionContext r)
    {
        return !r.IsSourceValueNull &&
               Mapper.FindTypeMapFor(sourceType, desitnationType).GetPropertyMaps().Where(
                   m => m.DestinationProperty.Name.Equals(r.MemberName)).Select(y => !y.IsMapped()).All(b => b);
    }

这就是它的使用方式(请注意,您需要在基类映射中使用ignore声明)

CreateMap<DerivedClassSource, DerivedClassDestination>()
            .InheritMappingFromBaseType()

它的作用是映射未使用基类映射映射的任何属性。换句话说,它打破了默认的映射优先级。

我找到了源代码here并对其进行了一些修改,因为一些原始方法的代码现在在AutoMapper 2和3中实现。

答案 3 :(得分:0)

在将此问题作为AutoMapper的问题引发之后,使用Include未添加Ignore的原因是因为没有办法取消忽略 - 仍然可以在基类中覆盖映射。

您目前可以实现此行为的唯一方法是使用[IgnoreMap]属性修饰目标属性,但这可能与您的其他配置不一致,因此您需要确定它是否是值得!