Automapper 没有传输我的 collection 项
Automapper is not transferring my collection items
我正在使用 AutoMapper 4.x。
我有几个类如下:
/// <summary>
/// All service outputs need to descend from this class.
/// </summary>
public class OzCpAppServiceOutputBase : IOzCpAppServiceOutputBase
{
private readonly OzCpResultErrors _OzCpResultErrors;
public OzCpAppServiceOutputBase()
{
_OzCpResultErrors = new OzCpResultErrors();
}
public OzCpResultErrors ResultErrors
{
get { return _OzCpResultErrors; }
}
public bool ResultSuccess
{
get { return _OzCpResultErrors.Messages.Count == 0; }
}
}
/// <summary>
/// Return from the booking service when a simple booking is made.
/// </summary>
public class OzCpSimpleManualCruiseBookingOutput : OzCpAppServiceOutputBase
{
public int OzBookingId { get; set; }
}
}
public class SimpleManualCruiseBookingOutput : OzCpSimpleManualCruiseBookingOutput
{
}
当我调用 AutoMapper 在 OzCpSimpleManualCruiseBookingOutput 和 SimpleManualCruiseBookingOutput 之间进行转换时,我的问题是结果错误已被清除。
public SimpleManualCruiseBookingOutput SimpleManualCruiseBooking(SimpleManualCruiseBookingInput aParams)
{
OzCpSimpleManualCruiseBookingOutput result = _PlatformBookingService.SimpleManualBooking(Mapper.Map<OzCpSimpleManualCruiseBookingInput>(aParams));
//**TESTING
result.ResultErrors.AddFatalError(1, "Oh Dear!!!!");
//**As soon as I perform the mapping the ResultErrros collection loses the item I have added above
return Mapper.Map<SimpleManualCruiseBookingOutput>(result);
}
我猜是因为它是只读的 属性,但我不知道如何让它传输 collection。
非常感谢任何帮助。
编辑
我自己也尝试在 collection 中添加项目,因此将我的映射从:
Mapper.CreateMap<OzCpSimpleManualCruiseBookingOutput, SimpleManualCruiseBookingOutput>();
使用after map函数如下:
Mapper.CreateMap<OzCpSimpleManualCruiseBookingOutput, SimpleManualCruiseBookingOutput>()
.AfterMap((src, dst) => dst.ResultErrors.Messages.AddRange(src.ResultErrors.Messages));
但这会导致目的地在列表中有 两个 个项目而不是 1 个项目,即:
与 "Oh Dear!!!!" 的条目相同
解决方案
使用 DavidL 建议的私有 setter 方法(以及对 Automapper 4.x 的升级)意味着我得到了所需的行为。所以这就是我最终得到的:
/// <summary>
/// Defines the contract for all output DTO's to platform
/// application services.
/// </summary>
/// <seealso cref="OzCpAppServiceOutputBase" />
public interface IOzCpAppServiceOutputBase : IOutputDto
{
/// <summary>
/// Contains a list of errors should a call to an application service fail.
/// </summary>
OzCpResultErrors ResultErrors{ get; }
/// <summary>
/// When TRUE the underlying call to the application service was successful, FALSE
/// otherwise. When FALSE see ResultErrors for more information on the error condition.
/// </summary>
bool ResultSuccess { get; }
}
public class OzCpAppServiceOutputBase : IOzCpAppServiceOutputBase
{
public OzCpAppServiceOutputBase()
{
ResultErrors = new OzCpResultErrors();
}
/// <remarks>The private setter is here so that AutoMapper works.</remarks>
public OzCpResultErrors ResultErrors { get; private set; }
public bool ResultSuccess
{
get { return ResultErrors.Messages.Count == 0; }
}
}
因此,虽然需要添加私有 setter "just for" AutoMapper,但只需付出很小的代价就可以完成这项工作,并且无需使用复杂的映射来处理该问题。
使用当前的继承结构,AutoMapper 将无法完成您希望它完成的工作。由于您的目标结构与源结构具有相同的属性,因此这些属性也是只读的。 AutoMapper 不会映射到没有声明 setter 的只读属性。
您有几个选择:
- 使 属性 setter 明确私有。 This 答案表明更高版本的 AutoMapper 支持此功能。在这种情况下,它适用于 4.x.
- 将 属性 setter 设为内部,这样只有该程序集的成员才能设置它。由于最新版本的 AutoMapper 将映射到私有 setters,因此它们也应该映射到内部 setters.
- 使 属性 可设置。
- 向下转换对象而不是映射(您已经提到您不想这样做,因为您的对象结构最终会发散)。
用 public setter 在目标对象上遮蔽 属性。丑陋且是奇怪错误的良好来源。
public class SimpleManualCruiseBookingOutput : OzCpSimpleManualCruiseBookingOutput
{
public new OzCpResultErrors ResultErrors { get; set; }
}
创建一个帮助程序,通过反射映射您的只读属性。 不要这样做!
PropertyInfo nameProperty = aParams.GetType().GetProperty ("ResultErrors");
FieldInfo nameField = nameProperty.GetBackingField ();
nameField.SetValue (person, aParams.ResultErrors);
我正在使用 AutoMapper 4.x。
我有几个类如下:
/// <summary>
/// All service outputs need to descend from this class.
/// </summary>
public class OzCpAppServiceOutputBase : IOzCpAppServiceOutputBase
{
private readonly OzCpResultErrors _OzCpResultErrors;
public OzCpAppServiceOutputBase()
{
_OzCpResultErrors = new OzCpResultErrors();
}
public OzCpResultErrors ResultErrors
{
get { return _OzCpResultErrors; }
}
public bool ResultSuccess
{
get { return _OzCpResultErrors.Messages.Count == 0; }
}
}
/// <summary>
/// Return from the booking service when a simple booking is made.
/// </summary>
public class OzCpSimpleManualCruiseBookingOutput : OzCpAppServiceOutputBase
{
public int OzBookingId { get; set; }
}
}
public class SimpleManualCruiseBookingOutput : OzCpSimpleManualCruiseBookingOutput
{
}
当我调用 AutoMapper 在 OzCpSimpleManualCruiseBookingOutput 和 SimpleManualCruiseBookingOutput 之间进行转换时,我的问题是结果错误已被清除。
public SimpleManualCruiseBookingOutput SimpleManualCruiseBooking(SimpleManualCruiseBookingInput aParams)
{
OzCpSimpleManualCruiseBookingOutput result = _PlatformBookingService.SimpleManualBooking(Mapper.Map<OzCpSimpleManualCruiseBookingInput>(aParams));
//**TESTING
result.ResultErrors.AddFatalError(1, "Oh Dear!!!!");
//**As soon as I perform the mapping the ResultErrros collection loses the item I have added above
return Mapper.Map<SimpleManualCruiseBookingOutput>(result);
}
我猜是因为它是只读的 属性,但我不知道如何让它传输 collection。
非常感谢任何帮助。
编辑
我自己也尝试在 collection 中添加项目,因此将我的映射从:
Mapper.CreateMap<OzCpSimpleManualCruiseBookingOutput, SimpleManualCruiseBookingOutput>();
使用after map函数如下:
Mapper.CreateMap<OzCpSimpleManualCruiseBookingOutput, SimpleManualCruiseBookingOutput>()
.AfterMap((src, dst) => dst.ResultErrors.Messages.AddRange(src.ResultErrors.Messages));
但这会导致目的地在列表中有 两个 个项目而不是 1 个项目,即:
与 "Oh Dear!!!!" 的条目相同 解决方案
使用 DavidL 建议的私有 setter 方法(以及对 Automapper 4.x 的升级)意味着我得到了所需的行为。所以这就是我最终得到的:
/// <summary>
/// Defines the contract for all output DTO's to platform
/// application services.
/// </summary>
/// <seealso cref="OzCpAppServiceOutputBase" />
public interface IOzCpAppServiceOutputBase : IOutputDto
{
/// <summary>
/// Contains a list of errors should a call to an application service fail.
/// </summary>
OzCpResultErrors ResultErrors{ get; }
/// <summary>
/// When TRUE the underlying call to the application service was successful, FALSE
/// otherwise. When FALSE see ResultErrors for more information on the error condition.
/// </summary>
bool ResultSuccess { get; }
}
public class OzCpAppServiceOutputBase : IOzCpAppServiceOutputBase
{
public OzCpAppServiceOutputBase()
{
ResultErrors = new OzCpResultErrors();
}
/// <remarks>The private setter is here so that AutoMapper works.</remarks>
public OzCpResultErrors ResultErrors { get; private set; }
public bool ResultSuccess
{
get { return ResultErrors.Messages.Count == 0; }
}
}
因此,虽然需要添加私有 setter "just for" AutoMapper,但只需付出很小的代价就可以完成这项工作,并且无需使用复杂的映射来处理该问题。
使用当前的继承结构,AutoMapper 将无法完成您希望它完成的工作。由于您的目标结构与源结构具有相同的属性,因此这些属性也是只读的。 AutoMapper 不会映射到没有声明 setter 的只读属性。
您有几个选择:
- 使 属性 setter 明确私有。 This 答案表明更高版本的 AutoMapper 支持此功能。在这种情况下,它适用于 4.x.
- 将 属性 setter 设为内部,这样只有该程序集的成员才能设置它。由于最新版本的 AutoMapper 将映射到私有 setters,因此它们也应该映射到内部 setters.
- 使 属性 可设置。
- 向下转换对象而不是映射(您已经提到您不想这样做,因为您的对象结构最终会发散)。
用 public setter 在目标对象上遮蔽 属性。丑陋且是奇怪错误的良好来源。
public class SimpleManualCruiseBookingOutput : OzCpSimpleManualCruiseBookingOutput { public new OzCpResultErrors ResultErrors { get; set; } }
创建一个帮助程序,通过反射映射您的只读属性。 不要这样做!
PropertyInfo nameProperty = aParams.GetType().GetProperty ("ResultErrors"); FieldInfo nameField = nameProperty.GetBackingField (); nameField.SetValue (person, aParams.ResultErrors);