如何忽略标记为虚拟的所有属性

时间:2014-07-06 14:56:20

标签: c# .net automapper

我在EF延迟加载的某些属性中使用virtual关键字。我有一个案例,在将源映射到目标时,应该从AutoMapper中忽略我的模型中标记为virtual的所有属性。

我是否可以通过自动方式实现此目的,还是应该手动忽略每个成员?

5 个答案:

答案 0 :(得分:28)

您可以创建映射扩展程序并使用它:

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

用法:

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

答案 1 :(得分:4)

inquisitive的答案可以正常使用,但是当从数据模型到服务模型执行某些映射并且应忽略源类型的虚拟成员时,它可以针对现实生活使用进行扩充。

此外,如果类型实现了某个接口,那么这些属性将显示为虚拟,因此必须添加!IsFinal条件以删除这些误报虚拟属性。

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

答案 2 :(得分:1)

当我们使用一些虚拟属性时,我不得不按如下方式重写扩展名:

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;

本质上,我检查该属性是否为ICollection<>类型或是否具有[ForeignKey]属性。

答案 3 :(得分:0)

要更正 @Alexei 的答案,请不要使用ForSourceMember方法,就像在github上的issu中回答的那样。只是为了验证。

另一种方法是像在answer中一样使用ForAllPropertyMaps

答案 4 :(得分:0)

以防万一,而无需配置第二个automapper实例 :

public static class ClearNavigationExtension
{
    public static void ClearNavigation(this object entity)
    {
        var type = entity.GetType();

        foreach (var property in type.GetProperties().Where(p => p.GetGetMethod().IsVirtual))
        {
            property.SetValue(entity, null);
        }
    }

    public static T ClearNavigation<T>(this T entity)
    {
        var type = entity.GetType();
        var entityCopy = Mapper.Map<T, T>(entity);

        foreach (var property in type.GetProperties().Where(p => p.GetGetMethod().IsVirtual))
        {
            property.SetValue(entityCopy, null);
        }

        return entityCopy;
    }

}