0.前置き

仕事でAutoMapperを触る機会がありました。
覚書のために、その記録を残しておきます。

1.AutoMapperとは

規約ベースで利用するオブジェクト-オブジェクトマッパーです。
(A convention-based object-object mapper. )
英語の訳をそのまま。。。

DTOからEntityやViewModelにデータを詰め直す時に使います。
詰め替えるコードをえんえんと書かなくてもOKというわけです。例えば以下のようなコードがあるとします。
[sourcecode language=”csharp”]
// 変換元を
SrcEmployee srcEmployee = …;

// 変換先に、詰め直す!
var destEmp = new DestEmployee
{
Name = srcEmp.Name,
Age = Convert.ToInt32(srcEmp.Age),
Status = EmployeeStatusResolver(srcEmp.Status),
HireDate = CustomDateTimeConverter(srcEmp.Status)
};
[/sourcecode]
規約に従えって、AutoMapperを利用すればこんな感じになります。(もろもろ省いています)
[sourcecode language=”csharp”]
Mapper.CreateMap<SrcEmployee, DestEmployee>();
var destEmp = Mapper.Map<SrcEmployee, DestEmployee>(srcEmp);
[/sourcecode]

2.インストール

AutoMapperのインストールはnugetでできます。とても簡単。

3.実際に使ってみる

課題を作って、実際に変換処理を書いて見ます。

3-1.(課題)変換元と変換先のクラス

SrcEmployeeからDestEmployeeにデータの詰め替えを行います。
(プロパティ名の対応関係の規約は、説明が煩雑になりそうなので省きます。)
[sourcecode language=”csharp”]
/// <summary>
/// 変換元のクラス
/// </summary>
public class SrcEmployee
{
public string Name { get; set; }
public string Age { get; set; }
public string Status { get; set; }
public DateTime HireDate { get; set; }
}

/// <summary>
/// 変換先のクラス
/// </summary>
public class DestEmployee
{
public string Name { get; set; }
public int Age { get; set; }
public EmployeeStatus Status { get; set; }
public string HireDate { get; set; }
}
[/sourcecode]

この課題に対して、型変換や、値の変換等、変換ルールが必要なところをマッピング定義に書いていきます。

3-2.グローバルな変換規則を作る

どのマッピングでも使うような変換規則を作ります。
今回は主に2つ。

  • stringをintに変換:Convet.ToInt32()を利用
  • DateTimeをstringに変換:独自のコンバーターを利用

作った独自のコンバーターはこんな感じ。
[sourcecode language=”csharp”]
public class CustomDateTimeConverter : TypeConverter<DateTime, string>
{
protected override string ConvertCore(DateTime source)
{
return source.ToString("yyyy年MM月dd日");
}
}
[/sourcecode]

3-3.変換元のクラスと変換先のクラスに依存する変換規則を作る

今回の例ですと、Statusというプロパティになります。
stringから、enumのEmployeeStatusに変換しています。今度は独自のリゾルバーを作ります。
[sourcecode language=”csharp”]
public class EmployeeStatusResolver : ValueResolver<SrcEmployee, EmployeeStatus>
{
protected override EmployeeStatus ResolveCore(SrcEmployee source)
{
switch (source.Status)
{
case "在職":
return EmployeeStatus.Stay;
case "退職":
return EmployeeStatus.Exit;
case "長期休暇中":
return EmployeeStatus.LongHoliday;
default:
throw new UnKnowonEmployeeStatusException();
}
}
}
[/sourcecode]

3-4.変換定義をする

今まで考えた変換定義をコードにおこします。
[sourcecode language=”csharp”]
// 2-2用のルール
Mapper.CreateMap<string, int>().ConvertUsing(Convert.ToInt32);
Mapper.CreateMap<DateTime, string>().ConvertUsing<CustomDateTimeConverter>();

// SrcEmployeeからDestEmployeeの変換定義と、2-3用のルール
Mapper.CreateMap<SrcEmployee, DestEmployee>()
.ForMember(dest => dest.Status, opt => opt.ResolveUsing<EmployeeStatusResolver>());
[/sourcecode]

3-5.マッピング

最後にマッピング!!これだけで、データの詰め直しが完了します。
[sourcecode language=”csharp”]
var destEmp = Mapper.Map<SrcEmployee, DestEmployee>(srcEmp);
[/sourcecode]

4.サンプルを書いてみての補足

最初にマッピングルールをいろいろ作らなきゃいけないのは面倒です。
ただかなりの確率で使いまわせることができるので、一回作ってしまえば良いです。

ASP.NET MVCで使うと便利だよ~って、マイコミジャーナルの記事でも言ってますので
興味のある方は、参考資料のほうをチェックしてみてください。

5.サンプルコード

サンプルコードはgithubにホスティングしてあります。
AutoMapperのサンプル
コード本体
※実は、初github!

6.参考資料

本家のページは以下です。CodePlexや、Google Groupsや、githubに情報が散らばってますけど、とりあえずここから行けばよし。
AutoMapperの本家のページ
マイコミジャーナルにも記事があったので載せておきます。
AutoMapperでオブジェクト間のデータコピーを行う