Automapperを使用して、ドメイン モデル ( nHibernate ) をビュー モデルにマップし、その逆にマップしています。すべてがとてもスムーズです。
ここで、エンティティ (ドメイン エンティティ) をそれ自体にマップする必要があるため、そこにいくつかのビジネス ルールを定義する必要があります。
同じ型に対して複数回異なるマッピングを定義する必要があります。私はすでに各タイプのマッピングにプロファイルを使用しています:
public static void Configure()
{
Mapper.Initialize(a =>
{
Mapper.AddProfile(new OrderViewModelMapperProfile());
Mapper.AddProfile(new OrderToOrder1MapperProfile());
Mapper.AddProfile(new OrderToOrder2MapperProfile());
});
}
そして、これは私のプロフィールです(簡略化):
public class OrderToOrder1MapperProfile : Profile
{
protected override void Configure()
{
this.CreateMap<Domain.Order, Domain.Order>()
.WithProfile("Profile001")
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty))
.ForMember(dest => dest.OrderLines, opt => opt.Ignore())
.AfterMap((source, destination) =>
{
foreach (var line in source.OrderLines)
{
destination.AddOrderLine(Mapper.Map<Domain.OrderLine, Domain.OrderLine>(line));
}
});
this.CreateMap<Domain.OrderLine, Domain.OrderLine>()
.ForMember(dest => dest.Order, opt => opt.Ignore())
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty));
}
}
ご覧のとおり、 AfterMapでいくつかのことを行う必要があります。
私の 2 番目のプロファイルOrderToOrder2MapperProfileは、ここに示すものと似ているため、コードは貼り付けません。
オブジェクトをマッピングすると:
Domain.Order order = new Domain.Order();
var order2 = Mapper.Map<Domain.Order, Domain.Order>(order);
両方のプロファイルが処理されます。
SO で提案されたパスに従うことにし、「カスタム」エンジンを作成しました。
private IMappingEngine CustomMappingEngine()
{
ConfigurationStore store = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
MappingEngine engine = new MappingEngine(store);
store.AddProfile(new OrderToOrder2MapperProfile());
store.AllowNullDestinationValues = true;
store.AssertConfigurationIsValid();
return (engine);
}
これで、行のマッピングを除いてすべて正常に動作します。カスタム エンジンを使用してオブジェクトをマップしている場合でも、両方のパイプが処理されます。
Domain.Order order = new Domain.Order();
var newEngine = CustomMappingEngine();
var order2 = newEngine.Map<Domain.Order, Domain.Order>(order);
問題は、ここでシングルトンマッパー(エンジン)を使用しているという事実にあると思います。
destination.AddOrderLine(Mapper.Map<Domain.OrderLine, Domain.OrderLine>(line))
プロファイラー内で現在のエンジンを使用する方法を見つけようとしましたが、それを取得できないようです。
唯一可能な解決策は、エンジンをプロファイラーのコンストラクターに渡すことです。
public class OrderToOrder2MapperProfile : Profile
{
private readonly IMappingEngine CurrentMappingEngine = null;
public OrderToOrder2MapperProfile(IMappingEngine mappingEngine)
{
this.CurrentMappingEngine = mappingEngine;
}
protected override void Configure()
{
this.CreateMap<Domain.Order, Domain.Order>()
.WithProfile("Profile002")
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty))
.ForMember(dest => dest.OrderLines, opt => opt.Ignore())
.AfterMap((source, destination) =>
{
foreach (var line in source.OrderLines)
{
destination.AddOrderLine(this.CurrentMappingEngine.Map<Domain.OrderLine, Domain.OrderLine>(line));
}
});
this.CreateMap<Domain.OrderLine, Domain.OrderLine>()
.ForMember(dest => dest.Order, opt => opt.Ignore())
.ForMember(dest => dest.Code, opt => opt.MapFrom(source => System.Guid.Empty));
}
}
ここで現在のエンジンを使用します。
destination.AddOrderLine(this.CurrentMappingEngine.Map<Domain.OrderLine, Domain.OrderLine>(line));
質問:
これが唯一の可能な解決策ですか、それともより良い代替手段がありますか?
私は物事を適切な方法で行っていますか?
誰かが興味を持っている場合は、 StructureMapをテスト ケースとして使用するgithub リポジトリを作成しました。