私はどこでも探していました:stackoverflow、automapper documentation、internets、これに関する情報を見つけることができませんでしたが、これも非常に一般的な問題のようです。
私のマッピング:
CreateMap<StatusLevelDTO, StatusLevel>()
.ForAllMembers(opt => opt.Condition(src => src != null));
これは、srcがソースプロパティではなくソースオブジェクト(StatusLevelDTO)を表すためだと思います(私は思う)。
具体的には、ObjectAをObjectBにマッピングし、ObjectA.SomeValueがnullでObjectB.SomeValueが2の場合、宛先オブジェクトにその値(2)を保持させます。
私はこの質問を見ました: Automapperはカスタムリゾルバでnull値をスキップします と最初の2つの答えを試しましたが、両方ともバージョン6では古いようです。
Automapper 6でこれを実現する方法はありますか?正確には6.0.2を使用しています。
メソッド Condition
には5つのオーバーロードがあり、そのうちの1つは型の述語を受け入れます
Func<TSource, TDestination, TMember, bool>
このTMemberパラメーターはソースメンバーです。したがって、nullのソースメンバーを確認できます。
CreateMap<StatusLevelDTO, StatusLevel>()
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
ソリューション here は、AutoMapper 6.0.2を使用している私のプロジェクトで機能します。 AutoMapper 4を使用した以前のプロジェクトでは、IsSourceValueNullを使用して同じ動作を実現していました。
元のソリューションに小さな変更を加えました。マップするプロパティのタイプをチェックする代わりに、ForAllPropertyMapsでフィルターを設定してソースオブジェクトのタイプをチェックし、カスタムリゾルバーがそのソースオブジェクトからのマップにのみ適用されるようにします。ただし、フィルタは必要に応じて任意に設定できます。
var config = new MapperConfiguration(cfg =>
{
cfg.ForAllPropertyMaps(
pm => pm.TypeMap.SourceType == typeof(<class of source object>),
(pm, c) => c.ResolveUsing<object, object, object, object>(new IgnoreNullResolver(), pm.SourceMember.Name));
});
class IgnoreNullResolver : IMemberValueResolver<object, object, object, object>
{
public object Resolve(object source, object destination, object sourceMember, object destinationMember, ResolutionContext context)
{
return sourceMember ?? destinationMember;
}
}
コメントする評判がないので、@ Sikor @senseiの回答をここに追加します。
DTOのNull許容データ型を持つモデルを使用している場合、以下のこの拡張メソッドを使用して、特定のデータ型のデフォルト値に依存するAutomapperの効果を無効にすることができます。
モデルの例
public class Foo {
public bool? Example { get; set; }
}
public class FooDto {
public bool Example { get; set; }
}
拡張方法:
public static TTarget MapModelProperties<TTarget, TSource>(this TTarget target, TSource source) where TTarget : class
where TSource : class
{
// Map target into the source, where the source property is null
Mapper.Initialize(cfg =>
{
cfg.CreateMap<TTarget, TSource>()
.ForAllMembers(opt => opt.Condition((src, dest, srcMember, destMember) => destMember == null));
});
Mapper.Map(target, source);
// Map the source into the target to apply the changes
Mapper.Initialize(cfg => cfg.CreateMap<TSource, TTarget>());
Mapper.Map(source, target);
return target;
}
使用法
public class Foo
{
public bool? Example { get; set; }
}
public class FooDto
{
public bool Example { get; set; }
}
public void Example()
{
var foo = new Foo
{
Example = null
};
var fooDto = new FooDto
{
Example = true
};
fooDto.MapModelProperties(foo);
}
これにより、Dtoプロパティ値が、nullであるすべてのモデルのプロパティ値にマップされます。次に、モデルプロパティ値をDtoにマップし直し、モデルに存在するDto値のみを変更します。
私は@Sergey Berezovskiy
の回答、およびメイン構成のすべてのマップのすべてのメンバーに対してこの構成を行いました。
Mapper.Initialize(cfg =>
{
cfg.ForAllMaps((obj, cnfg) => cnfg.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)));
}