けさらんぱさらん

方向性は定めず、ただ思いつくままに

AutoMapperでUpperCamelCaseとPascalCaseをMapする

今年、初ブログだったりします。(気力がね・・・)

さてタイトルの通りAutoMapperでUpperCamelCaseとPascalCaseをMapしたい。
C#でUpperCamelCaseを使うことはほぼ無いのですが
DBがOracleだったりしてORMもシンプルなものだったりすると
UpperCamelCaseで定義したクラスに一旦受けざる負えない時もあります。
それを簡単にPascalCaseで定義したクラスに移したいって時の話です。
(まああまり需要は無いですかねー)

以前に@xin9leさんが、このような記事を書かれています。
AutoMapperで特定の命名規則で変換する - xin9le.net
基本的にはこれでできたのですが、これにプラスして
PascalCaseからUpperCamelCaseへのMapもしたいのです。
これがかなり嵌りました。

とりあえずググる
Automapper: How to leverage a custom INamingConvention? - Stack Overflow
こんな感じで出てきますが、CreateProfileしてWithProfileするやり方だとどうもうまく行きませんでした。

で、ようやくできたのがこのやり方


とりあえず適当に受け渡しするクラスを作ります。

class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

class EmployeeDataModel
{
    public int EMPLOYEE_ID { get; set; }
    public string EMPLOYEE_NAME { get; set; }
}


INamingConventionを実装するクラスを作ります。

public class UpperSnakeCaseNamingConvention : INamingConvention
{
    public string SeparatorCharacter { get { return "_"; } }

    public Regex SplittingExpression { get { return new Regex(@"[\p{Lu}0-9]+(?=_?)"); } }
}


Profileクラスを継承するクラスをUpperCamelCaseからPascalCaseに変換するクラスと
逆にPascalCaseからUpperCamelCaseに変換するクラスを作ります。

class UpperSnakeToPascalProfile : Profile
{
    public override string ProfileName
    {
        get
        {
            return "UpperScakeToPascal";
        }
    }

    protected override void Configure()
    {
        // こちらはSourceに対して上で作ったINamingConventionを実装したクラスを設定
        this.SourceMemberNamingConvention = new UpperSnakeCaseNamingConvention();

        // 上の設定でMapしたいクラスは、ここでCreateMapすること
        this.CreateMap<EmployeeDataModel, Employee>();
    }
}

class PascalToUpperSnakeProfile : Profile
{
    public override string ProfileName
    {
        get
        {
            return "PascalToUpperSnake";
        }
    }

    protected override void Configure()
    {
        // こちらはDestinationに対して上で作ったINamingConventionを実装したクラスを設定
        this.DestinationMemberNamingConvention = new UpperSnakeCaseNamingConvention();

        this.CreateMap<Employee, EmployeeDataModel>();
    }
}


で、これを呼び出してうまく行くかテストします。

[TestClass]
public class UnitTest1
{
    public UnitTest1()
    {
        // Mappingの設定をする
        Mapper.Initialize(config =>
            {
                // AddProfileで上で作成したProfileクラスを設定
                config.AddProfile<UpperSnakeToPascalProfile>();
                config.AddProfile<PascalToUpperSnakeProfile>();
            });

        Mapper.AssertConfigurationIsValid();
    }

    [TestMethod]
    public void TestMethod1()
    {
        var dm = new EmployeeDataModel { EMPLOYEE_ID = 1, EMPLOYEE_NAME = "山田太郎" };
        var dto = Mapper.Map<Employee>(dm);

        Assert.AreEqual(dm.EMPLOYEE_ID, dto.EmployeeId);
        Assert.AreEqual(dm.EMPLOYEE_NAME, dto.EmployeeName);
    }

    [TestMethod]
    public void TestMethod2()
    {
        var dto = new Employee { EmployeeId = 2, EmployeeName = "佐藤一郎" };
        var dm = Mapper.Map<EmployeeDataModel>(dto);

        Assert.AreEqual(dto.EmployeeId, dm.EMPLOYEE_ID);
        Assert.AreEqual(dto.EmployeeName, dm.EMPLOYEE_NAME);
    }
}

という感じでちゃんとMapすることができました。