C# 映射忽略源对象中的所有空值属性

C# 映射忽略源对象中的所有空值属性,c#,.net,repository,automapper,C#,.net,Repository,Automapper,我正在尝试映射两个相同类型的对象。 我要做的是自动映射到igonore所有属性,这些属性在源对象中具有Null值,并在目标对象中保留现有值 我试着在我的“存储库”中使用它,但它似乎不起作用 Mapper.CreateMap<TEntity, TEntity>().ForAllMembers(p => p.Condition(c => !c.IsSourceValueNull)); Mapper.CreateMap().ForAllMembers(p=>p.Conditi

我正在尝试映射两个相同类型的对象。 我要做的是自动映射到igonore所有属性,这些属性在源对象中具有
Null
值,并在目标对象中保留现有值

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

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

有什么问题吗

到目前为止,我已经这样解决了

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);
    }

但是仍然希望找到一个使用AutoMapper的解决方案,这很有趣,但是你最初的尝试应该是可行的。以下测试为绿色:

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));
        }
    }
}
使用AutoMapper;
使用NUnit.Framework;
命名空间测试.UI
{
[测试夹具]
类自动映射测试
{
公共阶层人士
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共int?Foo{get;set;}
}
[测试]
公共void TestNullIgnore()
{
Mapper.CreateMap()
.ForAllMembers(opt=>opt.Condition(srs=>!srs.IsSourceValueNull));
var sourcePerson=新用户
{
FirstName=“比尔”,
LastName=“盖茨”,
Foo=null
};
var destinationPerson=新用户
{
FirstName=“”,
LastName=“”,
Foo=1
};
Mapper.Map(sourcePerson,destinationPerson);
Assert.That(destinationPerson,Is.Not.Null);
断言(destinationPerson.Foo,Is.EqualTo(1));
}
}
}
将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;
}

解决方法-在目标类型中添加DataMember属性[DataMember(EmitDefaultValue=false)]将在源值为null时删除该属性

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

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

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

如果角色值为null,则将删除角色属性。

条件
使用3个参数重载,让我们将表达式等效于示例
p.Condition(c=>!c.IsSourceValueNull)

方法签名:

void Condition(Func<TSource, TDestination, TMember, bool> condition
void条件(Func条件
等效表达式:

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

Hi,我们可以为所有类配置条件吗?我尝试了
Mapper.CreateMap
,但它不起作用(找不到类型或命名空间名称“tenty”)。谢谢。对于更高版本,答案是@nenad是正确的。您也可以检查这个答案:嗨,我们可以为所有类配置条件吗?我尝试了
Mapper.CreateMap
,但它不起作用(找不到类型或命名空间名称“tenty”)。谢谢。可能存在重复的
CreateMap<TSource, TDestination>.ForAllMembers(
    opt => opt.Condition((src, dest, sourceMember) => sourceMember != null));