AutoMapperの基本的な使い方サンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace TryAutoMapper | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using AutoMapper; | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
// | |
// AutoMapperは、ソースとなるオブジェクトとマッピング先のオブジェクト | |
// を指定することで同じプロパティ名を持つフィールドなどに値を自動でマッピングしてくれるライブラリ。 | |
// | |
// JavaのBeans.copyとかBeanUtils.copyPropertiesに似ている。 | |
// | |
// AutoMapperのインストールは、nugetから行える。 | |
// > Install-Package AutoMapper | |
// | |
// よく利用する場面として、ModelからDTOへの変換、またはその逆などがある。 | |
// | |
// | |
// AutoMapperでは、最初にマッピング定義を設定しておく必要がある | |
// | |
Mapper.CreateMap<Data1, DataDTO1>(); | |
// | |
// データを用意して、マッピング実行 | |
// | |
var data1 = new Data1 | |
{ | |
Id = 1, | |
Name = "hello world", | |
Age = 88 | |
}; | |
var dto = Mapper.Map<DataDTO1>(data1); | |
// | |
// マッピングされていることを確認 | |
// つまり、名前が一致するプロパティであれば自動的に値をマッピングしてくれる | |
// | |
var print = new Action<IData1>(item => | |
{ | |
Console.WriteLine("{0}, {1}, {2}", item.Id, item.Name, item.Age); | |
}); | |
print(data1); | |
print(dto); | |
// | |
// プロパティ名は同じだが、型が違う場合 | |
// そのままマッピングすると例外が発生する場合がある。 | |
// (発生しない場合もある。たとえば文字列で"333"と設定されていて、マップ先がintの場合などは | |
// デフォルトで、その型に紐づくTypeConverterが実行されるので正常に変換される。) | |
// | |
// そのままでは、変換できない場合はマッピング定義を作成する際に | |
// ForMemberメソッドで、どの値をマッピングして欲しいのかを設定しておく。 | |
// | |
Mapper.CreateMap<Data2, DataDTO2>() | |
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src => src.Value.Length)); | |
var data2 = new Data2 | |
{ | |
Value = "aaa" | |
}; | |
var dto2 = Mapper.Map<DataDTO2>(data2); | |
var print2 = new Action<dynamic>(obj => | |
{ | |
Console.WriteLine(obj.Value); | |
}); | |
print2(data2); | |
print2(dto2); | |
// | |
// プロパティ名が違う場合 | |
// そのままマッピングすると、当然ながらちゃんと値が設定されない。 | |
// やり方は、上述した「プロパティ名は同じだが、型が違う場合」と同じでResolveUsingを使う。 | |
// | |
Mapper.CreateMap<Data3, DataDTO3>() | |
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src => src.StringValue)); | |
var data3 = new Data3 | |
{ | |
StringValue = "hello world" | |
}; | |
var dto3 = Mapper.Map<DataDTO3>(data3); | |
Console.WriteLine(data3.StringValue); | |
Console.WriteLine(dto3.Value); | |
// | |
// マッピングする際に条件を付ける | |
// ある条件に基づいて、特定のプロパティに対してマッピングするか否かを判別出来る | |
// Conditionメソッドに条件を指定する | |
// | |
Mapper.CreateMap<Data4, DataDTO4>() | |
.ForMember(dest => dest.Value, opt => opt.Condition(src => src.Value < 10)); | |
// 条件を満たす値で試してみる | |
var data4_1 = new Data4 | |
{ | |
Value = 8 | |
}; | |
var dto4_1 = Mapper.Map<DataDTO4>(data4_1); | |
Console.WriteLine(data4_1.Value); | |
Console.WriteLine(dto4_1.Value); | |
// 条件を満たさない値で試してみる | |
var data4_2 = new Data4 | |
{ | |
Value = 50 | |
}; | |
var dto4_2 = Mapper.Map<DataDTO4>(data4_2); | |
Console.WriteLine(data4_2.Value); | |
Console.WriteLine(dto4_2.Value.HasValue); | |
// | |
// マッピング前とマッピング後に処理を実行する | |
// マッピング前に処理を挟むには、BeforeMapメソッド | |
// マッピング後に処理を挟むには、AfterMapメソッド | |
// を利用する | |
// | |
Mapper.CreateMap<Data5, DataDTO5>() | |
.BeforeMap((src, dest) => | |
{ | |
Console.WriteLine("x={0}, y={1}", src.X, src.Y); | |
}) | |
.AfterMap((src, dest) => | |
{ | |
dest.Total = src.X + src.Y; | |
}); | |
var data5 = new Data5 | |
{ | |
X = 100, | |
Y = 50 | |
}; | |
var dto5 = Mapper.Map<DataDTO5>(data5); | |
Console.WriteLine("src: x={0}, y={1}", data5.X, data5.Y); | |
Console.WriteLine("dest: x={0}, y={1}, total={2}", dto5.X, dto5.Y, dto5.Total); | |
// | |
// コレクション系 | |
// CreateMap<IEnumerable<XX>, IEnumerable<YY>> とかする必要はない。 | |
// 必要なのは、一対一のマッピングを普通に定義するだけ。 | |
// | |
Mapper.CreateMap<Data6, DataDTO6>(); | |
var data6 = Enumerable.Range(1, 10).Select(i => new Data6 { Value = i }); | |
var dto6 = Mapper.Map<IEnumerable<DataDTO6>>(data6); | |
var toCsv = new Func<IEnumerable<IData6>, string>(items => | |
{ | |
return items.Aggregate( | |
"", | |
(accum, item) => accum += item.Value + ",", | |
accum => accum.Substring(0, accum.Length - 1) | |
); | |
}); | |
Console.WriteLine(toCsv(data6)); | |
Console.WriteLine(toCsv(dto6)); | |
Console.ReadLine(); | |
} | |
} | |
#region IData1, Data1, DataDTO1 | |
internal interface IData1 | |
{ | |
int Id { get; set; } | |
string Name { get; set; } | |
int? Age { get; set; } | |
} | |
internal class Data1 : IData1 | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
public int? Age { get; set; } | |
} | |
internal class DataDTO1 : IData1 | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
public int? Age { get; set; } | |
} | |
#endregion | |
#region Data2, DataDTO2 | |
internal class Data2 | |
{ | |
public string Value { get; set; } | |
} | |
internal class DataDTO2 | |
{ | |
public int? Value { get; set; } | |
} | |
#endregion | |
#region Data3, DataDTO3 | |
internal class Data3 | |
{ | |
public string StringValue { get; set; } | |
} | |
internal class DataDTO3 | |
{ | |
public string Value { get; set; } | |
} | |
#endregion | |
#region Data4, DataDTO4 | |
internal class Data4 | |
{ | |
public int Value { get; set; } | |
} | |
internal class DataDTO4 | |
{ | |
public int? Value { get; set; } | |
} | |
#endregion | |
#region Data5, DataDTO5 | |
internal class Data5 | |
{ | |
public int X { get; set; } | |
public int Y { get; set; } | |
} | |
internal class DataDTO5 | |
{ | |
public int X { get; set; } | |
public int Y { get; set; } | |
public int Total { get; set; } | |
} | |
#endregion | |
#region IData6, Data6, DataDTO6 | |
internal interface IData6 | |
{ | |
int Value { get; set; } | |
} | |
internal class Data6 : IData6 | |
{ | |
public int Value { get; set; } | |
} | |
internal class DataDTO6 : IData6 | |
{ | |
public int Value { get; set; } | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment