我在下面的示例代码中得到一个“Nullable对象必须有值”。为什么我需要以下修复才能使其工作:
.ForMember(dest => dest.ShirtColor,
dest => dest.MapFrom(src => src.ShirtColor != null
? new OptionSetValue((int) src.ShirtColor)
: null))
AutoMapper.Mapper.CreateMap<PersonA, PersonB>()
.ForMember(dest => dest.FirstName, dest => dest.MapFrom(src => src.FirstName))
.ForMember(dest => dest.LastName, dest => dest.MapFrom(src => src.LastName))
// Condition to avoid overwriting existing data!!!
.ForMember(dest => dest.ShirtColor,
dest => dest.Condition(src => src.ShirtColor != null))
.ForMember(dest => dest.ShirtColor,
dest => dest.MapFrom(
src => new OptionSetValue((int)src.ShirtColor)))
// Fix that should not be needed due to condition:
//.ForMember(dest => dest.ShirtColor,
// dest => dest.MapFrom(
// src => src.ShirtColor != null
// ? new OptionSetValue((int) src.ShirtColor)
// : null));
PersonA source = new PersonA();
source.FirstName = "Thomas";
source.LastName = "Jefferson";
source.ShirtColor = null; // nullable int
PersonB destination = new PersonB();
destination.FirstName = "Thomas";
destination.LastName = "Jefferson";
destination.ShirtColor = new OptionSetValue(4);
// Results in: "Nullable object must have a value" despite the fact that
// condition should have been met!
Mapper.Map<PersonA, PersonB>(source, destination);
Debug.Assert(destination.ShirtColor != null);
Console.WriteLine("Our existing data was not overwritten!!");
Console.WriteLine("Hit enter to exit");
Console.ReadLine();
以下是OptionSet的定义方式: 公共类OptionSetValue { public OptionSetValue(){}
public OptionSetValue(int value)
{
Number = value;
}
public int Number { get; set; }
}
答案 0 :(得分:3)
您需要更改
.ForMember(dest => dest.ShirtColor,
dest => dest.Condition(src => src.ShirtColor != null))
到
.ForMember(dest => dest.ShirtColor,
opt => opt.Condition(src => !src.IsSourceValueNull))
请注意,您也不需要以下内容,因为它们按惯例映射:
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName))
更新 - 2
问题与条件和映射尚未组合的事实有关。我已经创建了一个简单的扩展方法来允许它。
这是一个演示它的测试
<强>类强>
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class PersonA : Person
{
public int? ShirtColor { get; set; }
}
public class PersonB : Person
{
public OptionSetValue ShirtColor { get; set; }
}
public class OptionSetValue
{
public int OptionSet { get; set; }
}
<强> MappingConfiguration 强>
public class MyProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<PersonA, PersonB>()
.ForMember(dest => dest.ShirtColor,
opt => opt.ConditionallyMapFrom(
src => new OptionSetValue
{
OptionSet = src.ShirtColor.Value
},
src => src.ShirtColor.HasValue));
}
}
public static class AutoMapperExtensions
{
public static void ConditionallyMapFrom<TSource, TMember>(
this IMemberConfigurationExpression<TSource> expression,
Expression<Func<TSource, TMember>> sourceMember,
Func<TSource, bool> condition)
{
expression.Condition(condition);
expression.MapFrom(sourceMember);
}
}
<强>单元测试强>
[TestFixture]
public class MappingTests
{
[Test]
public void AutoMapper_Configuration_IsValid()
{
Mapper.Initialize(m => m.AddProfile<MyProfile>());
Mapper.AssertConfigurationIsValid();
}
[Test]
public void AutoMapper_ClientMapping_IsValid()
{
Mapper.Initialize(m => m.AddProfile<MyProfile>());
Mapper.AssertConfigurationIsValid();
var source = new PersonA
{
FirstName = "FirstA",
LastName = "LastA",
ShirtColor = null
};
var destination = new PersonB
{
FirstName = "FirstB",
LastName = "LastB"
};
destination = Mapper.Map(source, destination);
Assert.That(destination, Is.Not.Null);
Assert.That(destination.FirstName, Is.EqualTo("FirstA"));
Assert.That(destination.LastName, Is.EqualTo("LastA"));
Assert.That(destination.ShirtColor, Is.Null);
}
}
答案 1 :(得分:2)
只需将其转换为可以为空的 int
:
.ForMember((destination) => destination.ShirtColor,
(memberConfiguration) => memberConfiguration.MapFrom((source) => (int?)source.ShirtColor))
答案 2 :(得分:2)
只需使用PreCondition
代替Condition
..
所以改变你的
//Condition to avoid overwriting existing data!!!
.ForMember(dest => dest.ShirtColor, dest => dest.Condition(src => src.ShirtColor != null))
.ForMember(dest => dest.ShirtColor, dest => dest.MapFrom(src => new OptionSetValue((int)src.ShirtColor)))
到
//Condition to avoid overwriting existing data!!!
.ForMember(dest => dest.ShirtColor, dest => dest.PreCondition(src => src.ShirtColor != null))
.ForMember(dest => dest.ShirtColor, dest => dest.MapFrom(src => new OptionSetValue((int)src.ShirtColor)))