ホームページ >バックエンド開発 >C#.Net チュートリアル >AutoMapper を使用して Dto と Model 間の自由な変換を実現する (パート 2)

AutoMapper を使用して Dto と Model 間の自由な変換を実現する (パート 2)

巴扎黑
巴扎黑オリジナル
2016-12-20 11:31:491745ブラウズ

本書は上記の続きです。前回の記事では、AutoMapper を使用して型間の 1-1 マッピングを実装する 2 つの方法 (規約と構成) について説明し、単純な OO マッピングを実行する方法を学びました。このシリーズの最後の記事では、型本体型間のマッピングを実装する方法、2 つの型に複数のマッピング ルールを実装する方法など、ニーズに基づいたいくつかの中レベルのトピックについて説明したいと思います。
[4] 型を型システムにマッピングする
まず、Dto と Model を確認します。 BookDto があり、著者がいて、各著者には独自の連絡先情報があります。ここで質問です。BookDto から最初の著者の Author オブジェクトを取得するにはどうすればよいですか?答えは簡単ですが、単純ではありません。
最も簡単な方法は、前述の CountructUsing を使用して、BookDto から Author へのすべてのフィールドとサブタイプ フィールドのマッピングを指定することです。構成(s => new Author {

name= s.firstauthorname、

説明= s.firstauthordescript、

contractInfo o {

bblog = s.firsauthorblog、

メール= S.Firstauthoremail、

;


このアプローチは機能する可能性がありますが、非常に不経済です。 BookDto から Author へのマッピングを最初から実行しており、BookDto から ContactInfo へのマッピングは以前に実装されているため、実際には再度記述する必要はありません。 ContactInfo も含まれる別の Reader 型がある場合、BookDto を Reader にマッピングするときに、BookDto -> ContactInfo ロジックを再度記述する必要があることを想像してください。もう一度想像してみてください。BookDto から Book へのマッピングを実装する場合、BookDto から Author へのマッピング ルールを再度記述する必要があるでしょうか?
したがって、型システム間のこの種のマッピングの理想的なアプローチは、特定の型ごとに単純なマッピングを指定し、複合型をマッピングするときにその単純な型のマッピングを再利用することだと思います。より簡単な言葉で説明してください:
4 つのタイプ A、B、C、D があります。ここで、B = [C, D]。 A -> C、A -> D の場合、A -> B を求めます。
私の解決策は、AutoMapper が提供する IValueResolver を使用することです。 IValueResolver は、フィールド レベルで特定のマッピング ロジックを実装するために AutoMapper によって定義された型です。その定義は次のとおりです。
実際のアプリケーションでは、その汎用サブクラスである ValueResolver を使用して、その抽象メソッドを実装することがよくあります。ターゲットフィールドのタイプ。

先ほどの例に戻り、次のように BookDto をマッピングできます -> 著者:

C# コード

var map = Mapper.CreateMap();

map.ForMember(d => d .Name, opt => opt.MapFrom(s => s.FirstAuthorName))

.ForMember(d => d.Description, opt => opt.MapFrom(s => s.FirstAuthorDescription) )

.ForMember(d => d.ContactInfo,


opt => opt.ResolveUsing()));

FirstAuthor In ContactInfoResolver では、ValueResolver を実装し、BookDto -> のロジックを再利用します。 ContactInfo :

C# コード


public class FirstAuthorContactInfoResolver : ValueResolver

{

protected override ContactInfo ResolveCore(BookDto ソース)

{

return Mapper.Map< BookDto、連絡先情報>(ソース);

}

}

すべてが完了しました。

同様に、BookDto -> Book を実装できるようになりましたね? BookDto -> Author と BookDto -> Publisher を再利用します。
本当に可能ですか?まだ問題がありそうです。はい、BookDto から 2 人の異なる著者にマッピングする必要があり、フィールド マッピング ルールが異なることがわかります。何をするか?早速最後のトピックに移りましょう。
[5] 2 つのタイプに対して複数セットのマッピング ルールを実装する

私たちの問題は、タイプ A と B について、2 つの異なる A -> B を定義し、それらを同時に使用できるようにする必要があることです。実際、現在の AutoMapper には、これを行うための既成の方法が提供されていません。もちろん、「国を救う曲線」メソッドを使用することもできます。FirstAuthor と SecondAuthor など、最初の著者と 2 番目の著者に対して Author の 2 つのサブクラスを定義し、BookDto ->FirstAuthor と BookDto -> を実装します。それぞれ SecondAuthor マッピング。しかし、この方法もあまり経済的ではありません。 3 人目の著者、さらには 4 人目の著者がいる場合はどうなるでしょうか?著者ごとに Author サブクラスを定義しますか?

一方、もし AutoMapper がそのような機能を提供したら、それはどのようになるだろうかと仮定することもできます。 CreateMap メソッドと Map メソッドは次のように定義する必要があります:

C# コード

CreateMap(string tag)

Map(TSource, string tag)

追加パラメータタグ このマッピングを識別するために使用されるラベル。

これを使用すると、次のことが可能になります。

C# コード

var firstAuthorMap = Mapper.CreateMap("first");

// BookDto を定義します -> 最初の著者ルール

var SecondAuthorMap = Mapper.CreateMap("first");

// BookDto を定義します -> var firstAuthor = Mapper.Map< ;BookDto, Author>(source, "first");

var SecondAuthor = Mapper.Map(source, "first");

残念ながら、これはすべて if です。しかし、それは問題ではありません。AutoMapper はこのドアを閉じましたが、MappingEngine という別のドアを残してくれました。

MappingEngine は AutoMapper のマッピング実行エンジンです。実際には、Mapper.CreateMap を呼び出すときに、このデフォルトの MappingEngine に対応するルールを記述し、Mapper.Map を呼び出してオブジェクトを取得します。場合によっては、対応する構成内のルールを実行するためにデフォルトの MappingEngine が使用されます。
要するに、MappingEngine は AutoMapper の「仮想マシン」です。複数の「仮想マシン」を同時に起動し、同じタイプのペアに対して異なるマッピング ルールを異なる「仮想マシン」に配置すると、それらをそれぞれ作成できます。それらを使用する場合は、対応する「仮想マシン」にどのルールを使用するかを問い合わせるだけです。
とにかくやってみよう。まず、MappingEngineProvider クラスを定義し、それを使用してさまざまな MappingEngine を取得します。

{

return _engine ;

}

}

さまざまなタイプのマッピング ルールをインターフェイス IMapping に抽象化します。

それではMappingEngineProvider のコンストラクター内の対応する MappingEngine に必要なルールを追加します:

C# コード

private static Dictionary> _rules=new Dictionary>();

public MappingEngineProvider(エンジンエンジン)

{

var config = new Configuration(new TypeMapFactory(), MapperRegistry.AllMappers());

_rules[エンジン].ForEach(r=> r.AddTo(config) ));

_mappingEngine = new MappingEngine(config);

ここでは、可能な MappingEngine を識別するために列挙型エンジンを使用していることに注意してください:

C# コード

public enum Engine

基本 = 0、

First、

Second

}

3 つのエンジンを使用します。Basic はすべての Dto ->FirstXXX ルールを配置するために使用され、Second はすべての Dto -> SecondXXX ルールを配置するために使用されます。

すべてのマッピング ルールを配置する辞書 _rule も定義し、ルールをさまざまなエンジンに分類します。

残っている唯一のことは、dictionary_rule にマッピングを記入することです。たとえば、最初のエンジンにbookdotopirstauthormingを配置し、2番目のエンジンにbookdotosecondauthormingを入れます;&gt;K New BookdTotofirstAutHormApping (),

}}, {

Engine.Second, New List & LT }}},};

もちろん、使いやすいように、別の MappingEngineProvider オブジェクトをインスタンス化することもできます。事前に:

C# コード

public static SimpleMappingEngineProvider First = new MappingEngineProvider(Engine.First);

public static SimpleMappingEngineProvider Second = new MappingEngine Provider(Engine.Second) ; これで、これら 2 つのエンジンを使用できるようになります。でBookDto -> をマッピングして 2 人の著者を取得し、それらを Book.Authors:

C# コード

public class BookDtoToBookMapping : DefaultMapping & LT; = & gt; d.authors,

OPT = & GT.ResolveUsing());



プライベート クラス AuthorsValueResolver>

{

を使用してuse using ‐ ' out out off out out out out way out's'' out's ‐ ‐ ‐ ‐ ‐ protected override List ResolveCore(BookDto ソース) Var firstautology = SimpleMappingengineProvider。 first.get (). マップ & lt; 著者 & gt; ()

; ? 新しいリスト<著者> ;() : 新しいリスト<著者> {新しい著者<著者}

: SecondAuthor.IsNull()

}

: new List {firstAuthor, SecondAuthor};

最後に、このセクションの冒頭で述べたご多幸をまだ覚えていますか? AutoMapper は実装に役に立たなかったので、自分で実装しましょう。

C# code

public class MyMapper

{

private static readonly Dictionary Engines = new Dictionary {tsource Source、Engine Engine = Engine.basic){

eensionエンジン[エンジン] .map&lt; tsource、ttarget&gt;(source);これを実行します:

C# コード

var firstAuthor = MyMapper.Map(dto, Engine.First);

var SecondAuthor = My Mapper(dto, Engine.Second) ;

は次のようにすることもできます:

C# code

var book = MyMapper.Map(dto);

追記: 自宅でGithubにファイルをアップロードするのが非常に遅いことがわかりました。ということで、まずはコードをパッケージ化してアップロードすることにしました。ぜひ参考にしてください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。