Подтвердить что ты не робот

AutoMapper.Map игнорирует все свойства нулевого значения из исходного объекта

Я пытаюсь отобразить 2 объекта одного типа. Я хочу, чтобы AutoMapper отображал все свойства, имеющие Null значение в исходном объекте и сохраняя существующее значение в целевом объекте.

Я пытался использовать это в своем "Репозитории", но, похоже, он не работает.

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

В чем может быть проблема?

4b9b3361

Ответ 1

Интересно, но твоя первоначальная попытка должна быть способ пойти. Ниже тест зеленый:

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

Ответ 2

До сих пор я решил это так.

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

Ответ 3

Condition перегрузка с тремя параметрами позволяет сделать выражение эквивалентным вашему примеру p.Condition(c => !c.IsSourceValueNull):

Подпись метода:

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

Эквивалентное выражение:

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

Ответ 4

Принимая решение 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;
}

Использование:

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

Ответ 5

Работа вокруг - добавление свойства 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 Свойство Role будет удалено.