AutoMapper.Map игнорирует все свойства нулевого значения из исходного объекта
Я пытаюсь отобразить 2 объекта одного типа.
Я хочу, чтобы AutoMapper отображал все свойства, имеющие Null
значение в исходном объекте и сохраняя существующее значение в целевом объекте.
Я пытался использовать это в своем "Репозитории", но, похоже, он не работает.
Mapper.CreateMap<TEntity, TEntity>().ForAllMembers(p => p.Condition(c => !c.IsSourceValueNull));
В чем может быть проблема?
Ответы
Ответ 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 будет удалено.