C# AutoMapper.Map 忽略源对象中的所有 Null 值属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12514084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 23:31:07  来源:igfitidea点击:

AutoMapper.Map ignore all Null value properties from source object

c#.netrepositoryautomapper

提问by Marty

I'm trying to map 2 objects of the same type. What I want to do is AutoMapper to igonore all the properties, that have Nullvalue in the source object, and keep the existing value in the destination object.

我正在尝试映射 2 个相同类型的对象。我想要做的是 AutoMapper 忽略所有Null在源对象中具有值的属性,并将现有值保留在目标对象中。

I've tried using this in my "Repository", but it doesn't seem to work.

我试过在我的“存储库”中使用它,但它似乎不起作用。

Mapper.CreateMap<TEntity, TEntity>().ForAllMembers(p => p.Condition(c => !c.IsSourceValueNull));

What might be the problem ?

可能是什么问题?

采纳答案by Void Ray

Interesting, but your original attempt should be the way to go. Below test is green:

有趣,但你最初的尝试应该是要走的路。下面的测试是绿色的:

using AutoMapper;
using NUnit.Framework;

namespace Tests.UI
{
    [TestFixture]
    class AutomapperTests
    {

      public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int? Foo { get; set; }
        }

        [Test]
        public void TestNullIgnore()
        {
            Mapper.CreateMap<Person, Person>()
                    .ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));

            var sourcePerson = new Person
            {
                FirstName = "Bill",
                LastName = "Gates",
                Foo = null
            };
            var destinationPerson = new Person
            {
                FirstName = "",
                LastName = "",
                Foo = 1
            };
            Mapper.Map(sourcePerson, destinationPerson);

            Assert.That(destinationPerson,Is.Not.Null);
            Assert.That(destinationPerson.Foo,Is.EqualTo(1));
        }
    }
}

回答by Marty

So far I've solved it like this.

到目前为止,我已经解决了这个问题。

foreach (var propertyName in entity.GetType().GetProperties().Where(p=>!p.PropertyType.IsGenericType).Select(p=>p.Name))
   {
      var value = entity.GetType().GetProperty(propertyName).GetValue(entity, null);
      if (value != null)
      oldEntry.GetType().GetProperty(propertyName).SetValue(oldEntry, value, null);
    }

but still hoping to find a solution using AutoMapper

但仍然希望使用 AutoMapper 找到解决方案

回答by primaryobjects

Taking Marty's solution (which works) one step further, here is a generic method to make it easier to use:

将 Marty 的解决方案(有效)更进一步,这里是一种使其更易于使用的通用方法:

public static U MapValidValues<U, T>(T source, U destination)
{
    // Go through all fields of source, if a value is not null, overwrite value on destination field.
    foreach (var propertyName in source.GetType().GetProperties().Where(p => !p.PropertyType.IsGenericType).Select(p => p.Name))
    {
        var value = source.GetType().GetProperty(propertyName).GetValue(source, null);
        if (value != null && (value.GetType() != typeof(DateTime) || (value.GetType() == typeof(DateTime) && (DateTime)value != DateTime.MinValue)))
        {
            destination.GetType().GetProperty(propertyName).SetValue(destination, value, null);
        }
    }

    return destination;
}

Usage:

用法:

class Person
{
    public string Name { get; set; } 
    public int? Age { get; set; } 
    public string Role { get; set; } 
}

Person person = new Person() { Name = "John", Age = 21, Role = "Employee" };
Person updatePerson = new Person() { Role = "Manager" };

person = MapValidValues(updatePerson, person);

回答by Srinath Subramani

Work Around - Add DataMember property in destination type [DataMember(EmitDefaultValue = false)]will remove the property if the source value is null.

变通方法- 在目标类型[DataMember(EmitDefaultValue = false)] 中添加 DataMember 属性将删除该属性,如果源值为 null。

[DataContract]
class Person
{
    [DataMember]
    public string Name { get; set; } 

    [DataMember]
    public int? Age { get; set; } 

    [DataMember(EmitDefaultValue = false)]
    public string Role { get; set; } 
}

if the Role value is null Role property will be removed.

如果 Role 值为 null Role 属性将被删除。

回答by Nenad

Conditionoverload with 3 parameters let's you make expression equivalent to your example p.Condition(c => !c.IsSourceValueNull):

Condition带有 3 个参数的重载让您使表达式等效于您的示例p.Condition(c => !c.IsSourceValueNull)

Method signature:

方法签名:

void Condition(Func<TSource, TDestination, TMember, bool> condition

Equivalent expression:

等价表达式:

CreateMap<TSource, TDestination>.ForAllMembers(
    opt => opt.Condition((src, dest, sourceMember) => sourceMember != null));