如何忽略所有标记为虚拟的属性
本文关键字:虚拟 属性 记为 何忽略 | 更新日期: 2023-09-27 18:11:34
我使用virtual
关键字的一些属性EF延迟加载。我有一种情况,在我的模型中标记为virtual
的所有属性在映射源到目标时都应该从AutoMapper忽略。
是否有一种自动的方法可以实现这一点,或者我应该手动忽略每个成员?
您可以创建一个映射扩展并使用它:
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();
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;
}
}
当我们使用一些虚拟属性时,我不得不重写扩展如下:
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]
属性。
要纠正@Alexei的答案,不要使用ForSourceMember
方法,就像在github上这个问题中回答的那样。这只是为了验证。
另一种方法是在这个答案中使用ForAllPropertyMaps
如果你想在不需要配置第二个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;
}
}