明示的にマップされているプロパティを除くすべてのプロパティを無視するようにAutoMapperに指示する方法はありますか?
外部から変更される可能性のある外部DTOクラスがあり、新しいプロパティを追加すると、それらを自分のオブジェクトにマップしようとすると機能が損なわれるため(例外が発生するため)、各プロパティを明示的に無視するように指定することは避けたいと思います。
明示的にマップされているプロパティを除くすべてのプロパティを無視するようにAutoMapperに指示する方法はありますか?
外部から変更される可能性のある外部DTOクラスがあり、新しいプロパティを追加すると、それらを自分のオブジェクトにマップしようとすると機能が損なわれるため(例外が発生するため)、各プロパティを明示的に無視するように指定することは避けたいと思います。
私が理解したことから、質問は、ソースにマップされたフィールドがない宛先にフィールドがあるということでした。そのため、これらのマップされていない宛先フィールドを無視する方法を探しています。
これらの拡張メソッドを実装して使用する代わりに、単に使用できます
Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Source);
これで、オートマッパーは、すべてのソース フィールドがマップされていることのみを検証する必要があり、その逆ではないことを認識します。
以下も使用できます。
Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Destination);
Can Gencer の拡張機能を更新して、既存のマップを上書きしないようにしました。
public static IMappingExpression<TSource, TDestination>
IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof (TSource);
var destinationType = typeof (TDestination);
var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType) && x.DestinationType.Equals(destinationType));
foreach (var property in existingMaps.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}
使用法:
Mapper.CreateMap<SourceType, DestinationType>()
.ForMember(prop => x.Property, opt => opt.MapFrom(src => src.OtherProperty))
.IgnoreAllNonExisting();
これは、宛先に存在しないすべてのプロパティを無視する、私が作成した拡張メソッドです。質問が2年以上前のものであるため、まだ役立つかどうかはわかりませんが、多くの手動の無視呼び出しを追加する必要がある同じ問題に遭遇しました。
public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>
(this IMappingExpression<TSource, TDestination> expression)
{
var flags = BindingFlags.Public | BindingFlags.Instance;
var sourceType = typeof (TSource);
var destinationProperties = typeof (TDestination).GetProperties(flags);
foreach (var property in destinationProperties)
{
if (sourceType.GetProperty(property.Name, flags) == null)
{
expression.ForMember(property.Name, opt => opt.Ignore());
}
}
return expression;
}
使用法:
Mapper.CreateMap<SourceType, DestinationType>()
.IgnoreAllNonExisting();
更新: カスタム マッピングがある場合、上書きされるため、明らかにこれは正しく機能しません。最初に IgnoreAllNonExisting を呼び出してから、後でカスタム マッピングを呼び出すと、まだ機能すると思います。
Mapper.GetAllTypeMaps()
schdr には、マップされていないプロパティを見つけてそれらを自動的に無視するために使用する解決策があります (この質問への回答として) 。私にはより堅牢なソリューションのようです。
私はこれを次の方法で行うことができました:
Mapper.CreateMap<SourceType, DestinationType>().ForAllMembers(opt => opt.Ignore());
Mapper.CreateMap<SourceType, DestinationType>().ForMember(/*Do explicit mapping 1 here*/);
Mapper.CreateMap<SourceType, DestinationType>().ForMember(/*Do explicit mapping 2 here*/);
...
注: AutoMapper v.2.0 を使用しています。
AutoMapper 5.0 の時点で、.TypeMap
プロパティ onIMappingExpression
はなくなりました。つまり、4.2 ソリューションは機能しなくなりました。元の機能を使用するが、構文が異なるソリューションを作成しました。
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Src, Dest>();
cfg.IgnoreUnmapped(); // Ignores unmapped properties on all maps
cfg.IgnoreUnmapped<Src, Dest>(); // Ignores unmapped properties on specific map
});
// or add inside a profile
public class MyProfile : Profile
{
this.IgnoreUnmapped();
CreateMap<MyType1, MyType2>();
}
実装:
public static class MapperExtensions
{
private static void IgnoreUnmappedProperties(TypeMap map, IMappingExpression expr)
{
foreach (string propName in map.GetUnmappedPropertyNames())
{
if (map.SourceType.GetProperty(propName) != null)
{
expr.ForSourceMember(propName, opt => opt.Ignore());
}
if (map.DestinationType.GetProperty(propName) != null)
{
expr.ForMember(propName, opt => opt.Ignore());
}
}
}
public static void IgnoreUnmapped(this IProfileExpression profile)
{
profile.ForAllMaps(IgnoreUnmappedProperties);
}
public static void IgnoreUnmapped(this IProfileExpression profile, Func<TypeMap, bool> filter)
{
profile.ForAllMaps((map, expr) =>
{
if (filter(map))
{
IgnoreUnmappedProperties(map, expr);
}
});
}
public static void IgnoreUnmapped(this IProfileExpression profile, Type src, Type dest)
{
profile.IgnoreUnmapped((TypeMap map) => map.SourceType == src && map.DestinationType == dest);
}
public static void IgnoreUnmapped<TSrc, TDest>(this IProfileExpression profile)
{
profile.IgnoreUnmapped(typeof(TSrc), typeof(TDest));
}
}
Automapper 5.0 の場合、マップされていないすべてのプロパティをスキップするには、配置する必要があります
.ForAllOtherMembers(x=>x.Ignore());
プロフィールの最後に。
例えば:
internal class AccountInfoEntityToAccountDtoProfile : Profile
{
public AccountInfoEntityToAccountDtoProfile()
{
CreateMap<AccountInfoEntity, AccountDto>()
.ForMember(d => d.Id, e => e.MapFrom(s => s.BankAcctInfo.BankAcctFrom.AcctId))
.ForAllOtherMembers(x=>x.Ignore());
}
}
この場合、出力オブジェクトの Id フィールドのみが解決され、他のすべてはスキップされます。魔法のように機能し、トリッキーな拡張機能はもう必要ないようです!
特定のメンバーを無視するようにどのように指定しますか? 適用したい規則、基本クラス、または属性はありますか? すべてのマッピングを明示的に指定する作業に取り掛かると、AutoMapper からどのような価値が得られるかわかりません。
これは古い質問のようですが、私のように見える他の人のために私の答えを投稿すると思いました.
私はConstructUsingを使用し、オブジェクト初期化子とForAllMembersを組み合わせて無視します。
Mapper.CreateMap<Source, Target>()
.ConstructUsing(
f =>
new Target
{
PropVal1 = f.PropVal1,
PropObj2 = Map<PropObj2Class>(f.PropObj2),
PropVal4 = f.PropVal4
})
.ForAllMembers(a => a.Ignore());
多くのメンバーを無視することについての唯一の情報は、このスレッドです-http: //groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f。PprovingCommonBaseClassConfigurationで使用されているトリックを使用して、同様のクラスの共通プロパティを無視できると思います。
また、「残りを無視する」機能に関する情報はありません。私は以前にコードを見たことがありますが、そのような機能を追加するのは非常に難しいように思われます。また、いくつかの属性を使用して、無視されたプロパティでマークを付けたり、マークされたすべてのプロパティを無視するための汎用/共通コードを追加したりすることもできます。
このように必要なだけ上書きするよりも、ForAllMembers を使用できます
public static IMappingExpression<TSource, TDest> IgnoreAll<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
{
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
注意してください。すべて無視されます。カスタム マッピングを追加しない場合、それらはすでに無視されており、機能しません。
また、AutoMapper の単体テストがあるかどうかを教えてください。そして、すべてのプロパティが正しくマッピングされたすべてのモデルをテストして、そのような拡張メソッドを使用しないでください
無視を明示的に書く必要があります
宛先タイプに存在しないプロパティを無視するための現在の (バージョン 9) ソリューションは、反転されたマッピングを作成し、それを逆にすることです。
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<TheActualDestinationType, TheActualSourceType>().ReverseMap();
});
3.3.1 のバージョンでは、単にIgnoreAllPropertiesWithAnInaccessibleSetter()
orIgnoreAllSourcePropertiesWithAnInaccessibleSetter()
メソッドを使用できます。