Automapper有条件地映射属性

时间:2017-12-04 06:26:07

标签: c# automapper

如何有条件地映射我的属性,值也是有条件的。 以下是我的代码详情: -

public class Team
{
    public string Id { get; set; }
    public Driver Driver { get; set; }
    public Driver Codriver { get; set; }
}

public class Driver
{
    public string DriverId { get; set; }
    public List<Score> Scores { get; set; }
}

public class Score
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    public string Value { get; set; }
    public int Score1 { get; set; }
    public int Score2 { get; set; }
}

我想移动司机和codriver。如果我想更新我的驱动程序,则Score1将更新,否则为Score2。如果我想用Driver更新它,那么Score1的细节将被移动,否则为Score2。我的映射如下: -

public void Move(Score sourceScore, string sourceType, Score targetScore, string targetType)
{
    Mapper.Initialize(cfg =>
    {
       cfg.CreateMap<Score, Score>()
       .ForMember(dest => dest.Score1, opt =>
       {
          opt.Condition((System.Func<Score, bool>) (src => string.Equals(targetType, "Driver")));
          opt.MapFrom(src => string.Equals(sourceType, "Driver") ? src.Score1 : src.Score2);
       })
       .ForMember(dest => dest.Score2, opt =>
       {
          opt.Condition((System.Func<Score, bool>) (src => string.Equals(targetType, "CoDriver")));
          opt.MapFrom(src => string.Equals(sourceType, "Driver") ? src.Score1 : src.Score2);
       });
    });

    Mapper.Map<Score, Score>(sourceScore, targetScore);    
}

上面完成的映射并没有正确映射细节。我错过了什么。有人可以帮我这个。

1 个答案:

答案 0 :(得分:0)

您必须检查您的逻辑并准确解释您想要获得的内容。目前您的代码执行此操作:

  1. 如果targetType"Driver"sourceType"Driver":目标中的Score1会获得来自Score1的值。
  2. 如果targetType"Driver"sourceType "Driver" 以外的任何内容:目标中的Score1将获得来自Score2的值。
  3. 如果targetType"CoDriver"sourceType"Driver",则目标中的得分2将获得来自Score1的值。
  4. 如果targetType"CoDriver"sourceType "Driver" 以外的任何内容:目标中的Score2将获得来自Score2的值。
  5. 如果这不是您想要的,请修改此规则,以便说明它。请注意,当您提出类似这样的问题时,您应该明确指出哪些内容没有按预期工作,并且理想情况下提供一个工作示例和一些指定所需行为的单元测试。像这样:

    我的代码:

    internal static class MappingDrivers
    {
        public static void Move(Score sourceScore, string sourceType, Score targetScore, string targetType)
        {
            Mapper.Initialize(cfg =>
            {
                cfg.CreateMap<Score, Score>()
                .ForMember(dest => dest.Score1, opt =>
                {
                    opt.Condition(src => string.Equals(targetType, "Driver"));
                    opt.MapFrom(src => string.Equals(sourceType, "Driver") ? src.Score1 : src.Score2);
                })
                .ForMember(dest => dest.Score2, opt =>
                {
                    opt.Condition(src => string.Equals(targetType, "CoDriver"));
                    opt.MapFrom(src => string.Equals(sourceType, "Driver") ? src.Score1 : src.Score2);
                });
            });
    
            Mapper.Map(sourceScore, targetScore);
        }
    }
    

    指定所需行为的单元测试:

    注意:我没有使用TestCase来保持简单

    internal class TestMappingDrivers
    {
        [Test]
        public void WhenTargetIsDriverAndSourceIsDriver_Score1GetsValueFromScore1()
        {
            int score1 = 666;
            var source = new Score
            {
                Score1 = score1,
                Score2 = 667
            };
            var destination = new Score();
    
            MappingDrivers.Move(source, "Driver", destination, "Driver");
    
            Assert.AreEqual(score1, destination.Score2);    // Intentionally failing, it should be Assert.AreEqual(score1, destination.Score1);
        }
    
        [Test]
        public void WhenTargetIsDriverAndSourceIsSomethingElse_Score1GetsValueFromScore2()
        {
            int score2 = 667;
            var source = new Score
            {
                Score1 = 666,
                Score2 = score2
            };
            var destination = new Score();
    
            MappingDrivers.Move(source, "SomethingElse", destination, "Driver");
    
            Assert.AreEqual(score2, destination.Score1);   // Passing
        }
    
        [Test]
        public void WhenTargetIsCoDriverAndSourceIsDriver_Score1GetsValueFromScore1()
        {
            int score1 = 666;
            var source = new Score
            {
                Score1 = score1,
                Score2 = 667
            };
            var destination = new Score();
    
            MappingDrivers.Move(source, "Driver", destination, "CoDriver");
    
            Assert.AreEqual(score1, destination.Score2);   // Passing
        }
    
        [Test]
        public void WhenTargetIsCoDriverAndSourceIsSomethingElse_Score1GetsValueFromScore2()
        {
            int score2 = 667;
            var source = new Score
            {
                Score1 = 666,
                Score2 = score2
            };
            var destination = new Score();
    
            MappingDrivers.Move(source, "SomethingElse", destination, "CoDriver");
    
            Assert.AreEqual(score2, destination.Score2);   // Passing
        }
    }
    

    另请注意,您应该只在应用程序启动期间初始化映射一次。每次调用Move函数时,您都在执行此操作。查看the docs

    最后,我会说你正在使用错误的工具来完成这项工作。 AutoMapper通常用于在两个不同的类之间进行映射,而不是从一个类的实例到同一个类的其他实例。你可以做到,但它“很奇怪”。我认为,对于你想要做的事情,正常的条件表达式(如果......其他)会更清楚地表达你的意图并且不易出错。