使用ValueInjector或Automapper时,如何防止“Source”对象中的值被“Source”对象覆盖?嵌套映射问题?

时间:2012-11-29 18:05:56

标签: automapper valueinjecter automapper-2

我的问题

“Source”对象View中不存在的同一个类的属性将使用null覆盖“Target”对象中的相同属性。我该如何防止这种情况?在影响中,我如何确保仅将填充(非空)属性合并到“目标”对象中。我也尝试使用Automapper,但失败了,但我很乐意将Automapper解决方案作为替代方案。

我很欣赏这个“Null Mapping”问题之前出现过,但我担心由于存在嵌套对象,我的情况更加复杂。好吧,我尝试了建议的选项,我无法让它们工作。我在这里。

非常感谢任何帮助。

我很欣赏这是一个复杂的问题,真的,非常感谢任何帮助,特别是如果有人可以为我生成代码示例。我已经把头发拉过来几天了:(

我的尝试

我有2个对象,一个是原始对象(“目标”),一个(“源”)由一个表单填充,即一个视图。

原始“目标”对象(myOrigDoc)如下所示:

enter image description here

表单“源”对象(myDoc)如下所示:

enter image description here

然后我做了映射:

            myOrigDoc.Introduction.InjectFrom<StrNotNull>(myDoc.Introduction);

使用以下注射器:

    public class StrNotNull: ConventionInjection
{
    bool blnNotNull = false;
    bool blnMatch = false;
    protected override bool Match(ConventionInfo c)
    {
        blnNotNull = false;
        blnMatch = false;

        //if ((c.SourceProp.Type == typeof(string)) && (c.SourceProp.Value != null))
        //    blnAssignable = true;

        if (c.SourceProp.Value != null)
            blnNotNull = true;

        if ((c.SourceProp.Name == c.TargetProp.Name) && (blnNotNull)) 
            blnMatch = true;

        return blnMatch;
    }
}

我最终得到了:

enter image description here

表单上没有“DateOfBirth”字段,因此我怀疑Model Binding在新的“MyDoc”对象上为“DataOfBirth”属性创建一个空值,当我调用时:

        public ActionResult Index(Document myDoc)

非常感谢,Ed。

EDIT1:我认为这是由于子类而导致的嵌套映射问题。不确定我如何在ValueInjector中对此进行排序。

EDIT2:来自嵌套映射文档的可能的Automapper解决方案,但我无法使其工作。我仍然将我的空值传递到目标。:

Mapper.CreateMap<XSD_Smart2.Document, XSD_Smart2.Document> 
().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));

Mapper.CreateMap<XSD_Smart2.DocumentIntroduction, XSD_Smart2.DocumentIntroduction>  
().ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));

Mapper.CreateMap<XSD_Smart2.Client, XSD_Smart2.Client>().ForAllMembers(opt => 
opt.Condition(srs => !srs.IsSourceValueNull));

2 个答案:

答案 0 :(得分:3)

更新ValueInjecter 3

public class IgnoreNulls : LoopInjection
{
    protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
    {
        var val = sp.GetValue(source);
        if (val != null)
        {
            tp.SetValue(target, val);
        }
    }
}

以前的版本

创建一个具有此行为的自定义注入:

    public class IgnoreNulls : ConventionInjection
    {
        protected override bool Match(ConventionInfo c)
        {
            return c.SourceProp.Name == c.TargetProp.Name
                  && c.SourceProp.Value != null;
        }
    }

并使用它:

    target.InjectFrom<IgnoreNulls>(source);

答案 1 :(得分:1)

这个简单的AutoMapper测试对我有用:

<强>类

public class Client
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

<强> AutoMapperConfiguration

public class MyProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Client, Client>()
            .ForAllMembers(opt => opt.Condition(src => !src.IsSourceValueNull));
    }
}

单元测试

[TestFixture]
public class MappingTests
{
    [Test]
    public void AutoMapper_Configuration_IsValid()
    {
        Mapper.Initialize(m => m.AddProfile<MyProfile>());
        Mapper.AssertConfigurationIsValid();
    }

    [Test]
    public void AutoMapper_ClientMapping_IsValid()
    {
        Mapper.Initialize(m => m.AddProfile<MyProfile>());
        Mapper.AssertConfigurationIsValid();

        var source = new Client
            {
                FirstName = "SourceFirstName1",
                LastName = null
            };

        var destination = new Client
            {
                FirstName = "DestinationFirstName1",
                LastName = "DestinationLastName1"
            };

        destination = Mapper.Map(source, destination);

        Assert.That(destination, Is.Not.Null);
        Assert.That(destination.FirstName, Is.EqualTo("SourceFirstName1"));
        Assert.That(destination.LastName, Is.EqualTo("DestinationLastName1"));
    }
}

<强>更新

有趣的是,当您使用此映射来映射列表时,它会失败。 IE - 此测试失败:

[Test]
public void AutoMapper_ClientListMapping_IsValid()
{
    Mapper.Initialize(m => m.AddProfile<MyProfile>());
    Mapper.AssertConfigurationIsValid();

    var source = new List<Client>
        {
            new Client
                {
                    FirstName = "SourceFirstName1",
                    LastName = null
                },
            new Client
                {
                    FirstName = null,
                    LastName = "SourceLastName2"
                }
        };

    var destination = new List<Client>
        {
            new Client
                {
                    FirstName = "DestinationFirstName1",
                    LastName = "DestinationLastName1"
                },
            new Client
                {
                    FirstName = "DestinationFirstName2",
                    LastName = "DestinationLastName2"
                }
        };

    destination = Mapper.Map(source, destination);

    Assert.That(destination, Is.Not.Null);
    Assert.That(destination.Count, Is.EqualTo(2));
    Assert.That(destination[0].FirstName, Is.EqualTo("SourceFirstName1"));
    Assert.That(destination[0].LastName, Is.EqualTo("DestinationLastName1"));
    //  /\  Line above went BANG!  /\
    Assert.That(destination[1].FirstName, Is.EqualTo("DestinationFirstName2"));
    Assert.That(destination[1].LastName, Is.EqualTo("SourceLastName2"));
}

这看起来像是AutoMapper中的一个错误(在2.2.0和2.2.1-ci9000中)