How to ignore all properties that are marked as virtual

…衆ロ難τιáo~ 提交于 2019-11-30 09:20:07
inquisitive

You can create a mapping extension and use it:

namespace MywebProject.Extensions.Mapping
{
    public static class IgnoreVirtualExtensions
    {
        public static IMappingExpression<TSource, TDestination>
               IgnoreAllVirtual<TSource, TDestination>(
                   this IMappingExpression<TSource, TDestination> expression)
        {
            var desType = typeof(TDestination);
            foreach (var property in desType.GetProperties().Where(p =>   
                                     p.GetGetMethod().IsVirtual))
            {
                expression.ForMember(property.Name, opt => opt.Ignore());
            }

            return expression;
        }
    }
}

Usage :

Mapper.CreateMap<Source,Destination>().IgnoreAllVirtual();

inquisitive's answer works fine, but it can be augmented for real life usage, when some mappings are performed from data models to service models and virtual members from source type should be ignored.

Also, if the type implements some interface, those properties will appear as virtual, so !IsFinal condition must be added to remove these false positive virtual properties.

public static class AutoMapperExtensions
{
    public static IMappingExpression<TSource, TDestination> IgnoreAllDestinationVirtual<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
    {
        var desType = typeof(TDestination);
        foreach (var property in desType.GetProperties().Where(p => p.GetGetMethod().IsVirtual && !p.GetGetMethod().IsFinal))
        {
            expression.ForMember(property.Name, opt => opt.Ignore());
        }

        return expression;
    }

    public static IMappingExpression<TSource, TDestination> IgnoreAllSourceVirtual<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
    {
        var srcType = typeof(TSource);
        foreach (var property in srcType.GetProperties().Where(p => p.GetGetMethod().IsVirtual && !p.GetGetMethod().IsFinal))
        {
            expression.ForSourceMember(property.Name, opt => opt.Ignore());
        }

        return expression;
    }
}

As we were using some virtual properties, I had to rewrite the extension as follows:

private static readonly Type CollectionBaseType = typeof(ICollection<>);

public static IMappingExpression<TSource, TDestination> IgnoreNavigationProperties<TSource, TDestination>(
    this IMappingExpression<TSource, TDestination> expression)
{
    var desType = typeof(TDestination);
    foreach (var property in desType.GetProperties()
                        .Where(p => IsCollectionProperty(p) || HasForeignKeyAttribute(p)))
    {
        expression.ForMember(property.Name, opt => opt.Ignore());
    }

    return expression;
}

private static bool IsCollectionProperty(PropertyInfo property)
{
    var propertyType = property.PropertyType;
    return propertyType.IsGenericType && 
           propertyType.GetGenericTypeDefinition() == CollectionBaseType;
}

private static bool HasForeignKeyAttribute(PropertyInfo property) =>
    property.GetCustomAttribute<ForeignKeyAttribute>() != null;

In essence I check if the property either is of type ICollection<> or if it has the [ForeignKey] attribute.

To correct the answer of @Alexei, don't use the ForSourceMember method, like it's answered here in this issu on github. It's just for validation.

An other way is to use ForAllPropertyMaps like in this answer.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!