次のようなソースオブジェクトと宛先オブジェクトがあります。
class ProductWithCategories // Source class
{
public Product Product { get; set; } // Product is an EF entity class
public IEnumerable<Category> Categories { get; set; }
}
class ProductViewModel // Dest class
{
public int Id { get; set; }
// Other properties with the same name as Product class
public IEnumerable<CategoryViewModel> Categories { get; set; }
}
したがって、source.Product
の値をdest
にマップし、次にsource.Categories
をdest.Categories
にマップする必要があります。 AutoMapperで可能ですか?
私はこれを試しました、そしてそれが失敗したとき私は驚きませんでした:
config.CreateMap<ProductWithCategories, ProductViewModel>()
.ForMember(q => q, option => option.MapFrom(q => q.Product))
.ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories));
これが私が受け取った例外です:
[AutoMapperConfigurationException:メンバーのカスタム構成は、タイプの最上位の個々のメンバーに対してのみサポートされています。]
OPとの議論の後、彼の主な必要性は、ソースオブジェクト内の子/ネストされたオブジェクトを、フラット化された宛先オブジェクトにすばやくマップすることであることがわかりました。彼は宛先のすべてのプロパティのマッピングを書きたくありません。
これを実現する方法を次に示します。
Product
-> ProductViewModel
を定義しますCategory
からCategoryViewModel
へのマッピングを定義するカテゴリをマップするマッピングProductWithCategories
-> ProductViewModel
を定義し、アフターマップでProduct
をマップします。
config.CreateMap<ProductWithCategories, ProductViewModel>() .ForMember(q => q.Id, option => option.Ignore()) // flattened in AfterMap .ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories)) .AfterMap((src, dst) => Mapper.Map(src.Product, dst));
AutoMapperの最新バージョンを使用すると、次のようなことができます。
config.CreateMap<Product, ProductViewModel>()
.ForMember(q => q.Categories, option => option.Ignore());
config.CreateMap<ProductWithCategories, ProductViewModel>()
.ConstructUsing(s => AutoMapper.Mapper.Map<ProductViewModel>(s.Product))
.ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories))
.ForAllOtherMembers(o => o.Ignore();
ConstructUsing()を使用して、ソースのネストされたchild [ren]から基本クラスを生成し、データを設定します。そのようなネストされた子が複数ある場合、最初のMap()呼び出しによって生成されたインスタンスに連続してそれぞれをマッピングするために、いくつかのマッピング呼び出しを行う必要があります。 .ForAllOtherMembers()は比較的最近のものです(それがない場合は、新しいバージョンのAutoMapperを入手してください)。残念ながら、マッピングが必要であるがマップの更新を忘れている宛先メンバーを追加する場合、構成の検証は行われないため、少し安全ではありません。捕まえろ。
エラーを生成する問題の行は
.ForMember(q => q, option => option.MapFrom(q => q.Product))
エラーメッセージはわかりにくいですが、宛先プロパティを明示的に記述する必要があります。
.ForMember(q => q.Id, option => option.MapFrom(q => q.Product.Id))
.ForMember(q => q.OtherProperty, option => option.MapFrom(q => q.Product.OtherProperty))
また、Category
からCategoryViewModel
へのマッピングを定義する必要があります。
.ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories))
働く:
config.CreateMap<Category, CategoryViewModel>();
あなたはそうするべきです-
AutoMapper.Mapper.CreateMap<Category, CategoryViewModel>();
AutoMapper.Mapper.CreateMap<ProductWithCategories, ProductViewModel>()
.ForMember(a => a.Id, b => b.ResolveUsing(c => c.Product != null ? c.Product.MyProperty : 0))
.ForMember(a => a.Categories, b => b.ResolveUsing(c => c.Categories));
ただし、ProductViewModel
(Id
のようなプロパティ)からこれらのプロパティを別のクラス内にラップすることをお勧めします。そして、オートマッパーのように動作するように別のマップを作成します。