【问题标题】:How to ignore all properties that are marked as virtual如何忽略所有标记为虚拟的属性
【发布时间】:2014-07-06 14:56:19
【问题描述】:

我在我的一些属性中使用virtual 关键字来进行 EF 延迟加载。我有一种情况,在将源映射到目标时,我的模型中标记为 virtual 的所有属性都应该被 AutoMapper 忽略。

有没有一种自动方法可以实现这一点,还是应该手动忽略每个成员?

【问题讨论】:

  • 您不能在开箱即用的自动映射器中执行此操作,但您可以使用此规则在代码中创建地图。
  • 很好奇,为什么要忽略这些?如果您想忽略它们,为什么它们会出现在您的目标类型上?
  • 这些是 EF Code First 模型中其他实体的导航属性。创建新条目时,我需要将视图模型与表单中的数据映射到域模型(Ef Code First 模型)中的属性。通常不映射属性不会导致任何错误或异常,但我在单元测试中使用 AutoMapper 的 Mapper.AssertConfigurationIsValid(),如果我没有映射目标模型的所有属性,则断言会引发异常

标签: c# .net automapper


【解决方案1】:

您可以创建一个映射扩展并使用它:

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

【讨论】:

  • 感谢 Scott Chamberlain 添加缺失的括号
  • 这是一个很好的解决方案,而且看起来是代码中唯一的错误,所以我修复了它。
  • @ScottChamberlain 嗯,你说的唯一错误?您添加括号的方法名称也不太正确。 ;)
  • 请注意,接口中定义的属性始终是虚拟的。一种解决方案是将!p.GetGetMethod().IsFinal 添加到Where 谓词中。 stackoverflow.com/a/4793253/941764
  • 谢谢!如果您不介意,您会根据@jgillich 提出的建议编辑您的答案吗?
【解决方案2】:

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

【讨论】:

  • 谢谢。我发现由于这些误报而被忽略的各种属性。这应该是正确的、被接受的答案。
【解决方案3】:

由于我们使用了一些虚拟属性,我不得不重写扩展如下:

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&lt;&gt; 类型,或者是否具有[ForeignKey] 属性。

【讨论】:

    【解决方案4】:

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

    另一种方法是使用ForAllPropertyMaps,就像在这个answer中一样。

    【讨论】:

      【解决方案5】:

      如果您想在不需要配置第二个自动映射器实例的情况下这样做 :

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-11
        • 1970-01-01
        • 2010-10-06
        • 1970-01-01
        • 2011-09-05
        • 2014-03-08
        • 1970-01-01
        相关资源
        最近更新 更多