3

ドメインのオブジェクトにマップする必要がある DTO が多数あります。一般に、金額へのマッピングでは丸めルールを適用する必要があります。これは 95% 以上のケースに当てはまりますが、別の丸め規則が必要なデータがいくつかあります。私は次のことを計画していました:

1) この型変換のデフォルトに適用される一般的な丸めルールの ITypeConverter を作成します。

2) 特殊な丸めのケース用に ValueResolver を作成し、メンバー マッピングでの使用を指定します。

私は自分のアプローチを試すためにテスト ケースを作成しましたが、特殊なケースに ValueResolver を適用した後、AutoMapper は TypeConverter を使用して、一般的なルールを使用して最終的な値を取得します。

それは間違ったアプローチですか?? 私は何かが欠けているかもしれませんか??

次に、テスト ケース:

[TestFixture]
public class RoundingTests
{
    public class MoneyConverter : ITypeConverter<decimal, decimal>
    {
        public decimal Convert(ResolutionContext context)
        {
            return Math.Round((decimal)context.SourceValue, 2, MidpointRounding.AwayFromZero);
        }
    }

    public class Money12Resolver : ValueResolver<decimal, decimal>
    {
        protected override decimal ResolveCore(decimal source)
        {
            return Math.Round(source, 12, MidpointRounding.AwayFromZero);
        }
    }

    public class PercentResolver : ValueResolver<decimal, decimal>
    {
        protected override decimal ResolveCore(decimal source)
        {
            return Math.Round(source, 4, MidpointRounding.AwayFromZero);
        }
    }
    internal class Source
    {
        public decimal Price { get; set; }
        public decimal Percent { get; set; }
        public decimal Prorate { get; set; }
    }

    internal class Destination
    {
        public decimal Price { get; set; }
        public decimal Percent { get; set; }
        public decimal Prorate { get; set; }
    }

    [Test]
    public void MappingTest()
    {
        Mapper.CreateMap<decimal, decimal>().ConvertUsing<MoneyConverter>();

        Mapper.CreateMap<Source, Destination>()
            .ForMember(d => d.Percent, o => o.ResolveUsing<PercentResolver>().FromMember(s => s.Percent))
            .ForMember(d => d.Prorate, o => o.ResolveUsing<Money12Resolver>().FromMember(s => s.Prorate));

        Mapper.AssertConfigurationIsValid();

        var source = new Source
                     {
                         Price = 12345.6789m,
                         Percent = 0.123456m,
                         Prorate = 123.123451234512345m
                     };

        var convertion = Mapper.Map<Destination>(source);

        Assert.That(convertion, Is.Not.Null);

        Assert.That(convertion.Price, Is.EqualTo(12345.68m));
        Assert.That(convertion.Percent, Is.EqualTo(0.1235m));
        Assert.That(convertion.Prorate, Is.EqualTo(123.123451234512m));
    }
}

テスト結果:

  Expected: 0.1235m
  But was:  0.12m
4

1 に答える 1

0

を使用してすべての decimal->decimal マッピングを変換するように AutoMapper に指示していますMoneyConverter。実際、AutoMapper はリゾルバーを使用しますが (ブレーク ポイントを設定して確認します)、解決の結果は 10 進数値であり、MoneyConverter適用した によって使用されます。

注:これは AutoMapper の設計のようです。型コンバーターをオーバーライドする方法がわかりません。

すべての小数プロパティが金額を表しているわけではないため、別のアプローチを取ることをお勧めします。また、プレゼンテーションに使用する値だけを丸めているのか、それともドメイン オブジェクトで保持したい精度が失われる可能性があるのか​​、自問してみてください。丸めが本当に必要な場合は、コンバーターを完全にスキップして、明示的にメンバーごとにリゾルバーを設定できます。または、例外であるメンバーを無視して、.ConstructUsing(...).

ただし、元の質問は同じタイプのリゾルバーとコンバーターの使用に関連しているため、これを機能させる方法の 1 つを次に示します。


基本的に、コンバーターが特定のプロパティのデフォルトの変換をスキップするようにします。構成を介して行うことはできないため、実行時に行う必要があります。クラスにアクセスできると仮定するとDestination、カスタム属性を使用してデフォルト以外の動作でプロパティを装飾するだけです。

class PercentAttribute : Attribute
{   }

class Destination
{
    [Percent]
    public decimal Percent { get; set; }
    ...
}

コンバーターで、 であるプロパティを探して[Percent]、ソース値を返すことができますPercentResolver

public class MoneyConverter : ITypeConverter<decimal, decimal>
{
    public decimal Convert(ResolutionContext context)
    {
        var propInfo = context.PropertyMap.DestinationProperty.MemberInfo;
        bool isPercent = propInfo.GetCustomAttributes(typeof(PercentAttribute), true).Any();
        if (isPercent) return (decimal)context.SourceValue;

        return Math.Round((decimal)context.SourceValue, 2, MidpointRounding.AwayFromZero);
    }
}

そのルートに行く場合は、属性に基づいてコンバーターに Money、Percent、および Money12 の変換を行わせ、リゾルバーを完全にスキップします。

于 2015-11-25T18:58:06.210 に答える