我正在尝试映射 2 个相同类型的对象。我想要做的是 AutoMapper 忽略所有Null
在源对象中具有值的属性,并将现有值保留在目标对象中。
我已经尝试在我的“存储库”中使用它,但它似乎不起作用。
Mapper.CreateMap<TEntity, TEntity>().ForAllMembers(p => p.Condition(c => !c.IsSourceValueNull));
可能是什么问题?
我正在尝试映射 2 个相同类型的对象。我想要做的是 AutoMapper 忽略所有Null
在源对象中具有值的属性,并将现有值保留在目标对象中。
我已经尝试在我的“存储库”中使用它,但它似乎不起作用。
Mapper.CreateMap<TEntity, TEntity>().ForAllMembers(p => p.Condition(c => !c.IsSourceValueNull));
可能是什么问题?
有趣,但你最初的尝试应该是要走的路。下面的测试是绿色的:
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));
}
}
}
Condition
使用 3 个参数重载让您使表达式等效于您的示例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));
到目前为止,我已经这样解决了。
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 找到解决方案
将 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);
解决方法 -如果源值为 null,则在目标类型[DataMember(EmitDefaultValue = false)]中添加 DataMember 属性将删除该属性。
[DataContract]
class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int? Age { get; set; }
[DataMember(EmitDefaultValue = false)]
public string Role { get; set; }
}
如果 Role 值为 null,则将删除 Role 属性。