简体   繁体   English

Automapper-忽略基类的属性

[英]Automapper - Ignore property on base class

I'm having difficulty ignoring a property on an class which inherits from a base class. 我很难忽略从基类继承的类的属性。

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

Mapper.CreateMap<FormViewModel, Entity>();

The only thing to note here is that the property on the base class is String and the property on the derived class is a Int32. 这里唯一需要注意的是,基类的属性是String,派生类的属性是Int32。

No matter what, when i try map an instance of FormViewModel to Entity the String based Id property on the Entity class is always set to the Int value from the FormViewModel, even though i have specified to ignore it. 无论如何,当我尝试将FormViewModel的实例映射到Entity时,即使我已指定忽略它,但Entity类上基于String的Id属性始终设置为FormViewModel的Int值。

The reason I am using different types for the Id on FormViewModel and Entity, is that I am using RavenDB in a web app and objects can be loaded via a string or an int Id. 我对FormViewModel和Entity使用不同类型的ID的原因是,我在Web应用程序中使用RavenDB,并且可以通过字符串或int Id加载对象。 On the client-side Int Id's are preferred as the standard Raven string based ID's do not play well when generating links. 在客户端,最好使用Int Id,因为基于标准Raven字符串的ID在生成链接时不能很好地发挥作用。

Can anyone tell me what the problem is here ? 谁能告诉我这里是什么问题?

So your base class looks something like this? 那么您的基类看起来像这样吗?

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

and your derived class looks like this? 您的派生类如下所示?

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

I'm assuming that's the case. 我以为是这样。

And if that's the case, then the derived Id is hiding the base Id property. 如果是这种情况,则派生的Id隐藏了基本Id属性。

Anyway, so are you passing around actual instances of a FormViewModel and making Entity objects from them? 无论如何,您是否传递了FormViewModel实际实例并从中创建Entity对象?

I see this line: 我看到这一行:

Mapper.CreateMap<FormViewModel, Entity>();

Which says to me "make me a new Entity object from the FormViewModel object I send you and do the default, conventional thing to accomplish this." 这对我说:“从发送给我的FormViewModel对象中创建一个新的Entity对象,并执行默认的常规操作来完成此任务。”

So when you call something like: 因此,当您调用类似的内容时:

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

It's going to use that Map, not the one for the base object. 将使用该Map,而不是用于基础对象的Map。 Because it is a derived FormViewModel . 因为它派生的FormViewModel

If you did something like: 如果您做了类似的事情:

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

to handle the mapping of your derived object, it would map it, I suspect, as you would want but it might be helpful to understand a bit more about what you're trying to do. 我怀疑,如果要处理派生对象的映射,它会映射它,但是了解更多有关您要执行的操作可能会有所帮助。

You'll need to specify mapping details (like ignoring certain properties) in the mapping of child classes , not parents. 您需要在子类而非父的映射中指定映射详细信息(例如忽略某些属性)。 For example: 例如:

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

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

The reason your code is not working is that you're specifying Ignore() on the parent mappings. 您的代码无法正常工作的原因是您在父级映射上指定了Ignore()。

I know this question is a year old but I haven't found a solution in SO that answers this kind of questions. 我知道这个问题已经一岁了,但是我还没有找到可以回答此类问题的解决方案。 I had identical issue and after some digging the only thing I found is that this behavior is not very well documented. 我遇到了相同的问题,经过一番挖掘后,我发现唯一的发现是这种行为没有得到很好的记录。 And mapping base classes works but ignoring them doesn't for some reason. 映射基类是可行的,但是由于某些原因却不能忽略它们。

I used this extension method and it worked out for me 我使用了这种扩展方法,并为我解决了

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);
    }

And this is how it's used (Notice that you will need to but the ignore declaration in the base classes mapping) 这就是它的使用方式(请注意,您将需要但要忽略基类映射中的ignore声明)

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

What it does is mapping any properties that were not mapped using the base class mapping. 它所做的是映射未使用基类映射映射的任何属性。 In other words it breaks the default mapping priorities. 换句话说,它破坏了默认的映射优先级。

I found the source code here and modified it a bit because some of the original method's code is now implemented in AutoMapper 2 and 3. 我在这里找到了源代码并对其进行了修改,因为一些原始方法的代码现在已在AutoMapper 2和3中实现。

After raising this as an issue with AutoMapper, the reason that Ignore is not added using Include is because there is no way to un-ignore - mappings can still be overridden in the base class. 在AutoMapper提出这个问题之后,未使用Include不添加Ignore的原因是因为无法忽略-映射仍可在基类中覆盖。

The only way that you can currently achieve this behaviour is to decorate the destination property with the [IgnoreMap] attribute, but this will likely be inconsistent with the rest of your configuration, so you'd need to decide whether it's worth it! 当前可以实现此行为的唯一方法是用[IgnoreMap]属性装饰destination属性,但这可能与其余配置不一致,因此,您需要确定是否值得!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM