AutoMapper与POST请求的实际用法

时间:2014-12-06 14:58:02

标签: asp.net entity-framework automapper dto

GET请求中,我可以轻松地创建从后端模型到具有AutoMapper的自定义DTO的映射。但是,在将AutoMapperPOST请求一起使用时,我有些担忧。

假设用户在线订购产品,他向服务器发送包含一些所需数据的POST请求。事实是,并非后端模型中的每个数据都是由用户发送的。我们假设ID的{​​{1}}是Order,当条目插入数据库时​​会自动生成GUID;或者可能还有其他属性自动递增。所有这些无法映射的属性都会导致很多.ForMember(dest => dest.myProperty, opt => opt.Ignore())个链,以及var mappedInstance = Mapper.Map<PostDTO, BackEndModel>(postDTO)之后对映射实例的额外处理。

AutoMapper是不是针对上述情况而设计的?如果后端模型比DTO复杂得多,那么处理模型映射过程的做法是什么?


更新

public class MultipleChoiceQuestion
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid MultipleChoiceQuestionId { get; set; }
    [Required]
    public string Question { get; set; }
    [Required]
    public ICollection<PossibleChoice> PossibleChoices { get; set; }
}

public class PossibleChoice
{
    [Key, Column(Order = 1), ForeignKey("MultipleChoiceQuestion")]
    public Guid MultipleChoiceQuestionId { get; set; }
    [Key, Column(Order = 2)]
    public int ChoiceIndex { get; set; }
    [Required]
    public string AnswerText { get; set; }

    public MultipleChoiceQuestion MultipleChoiceQuestion { get; set; }
}

用户发送创建新问题的请求。只发送了2个字段。

{
    "Question": "How are you?",
    "Answers": [
        { "Text": "I am fine." },
        { "Text": "Feeling bad." }
    ]
}

此阶段缺少的属性:

  • MultipleChoiceQuestionId
    • 插入后生成
  • ChoiceIndex
    • 自动从1增加到可用答案数

如果没有手动映射,如何使用AutoMapper处理这种情况?

2 个答案:

答案 0 :(得分:0)

我不确定您在架构中的哪个位置使用AutoMapper,但在执行自动化之前,您可以在概念上将属性列入白名单。例如,如果您在MVC中并且正在进行模型绑定,则有一些技术(例如在UpdateModel方法中)包含或排除属性列表。

答案 1 :(得分:0)

1-定义您的DTO是这样的:

public class MultipleChoiceQuestionDto
{
    // This property could stay here, because you may need to use the same DTO for update (PUT), 
    // which means you need the Id to distinguish and validate the DTO data against the URL id
    //public Guid MultipleChoiceQuestionId { get; set; } 

    public string Question { get; set; }

    public ICollection<PossibleChoiceDto> PossibleChoices { get; set; }
}

public class PossibleChoiceDto
{
    // This can go from this dto, because this DTO is a child dto for its parent.
    //public Guid MultipleChoiceQuestionId { get; set; }

    // This property could stay here, because you may need to use the same DTO for update (PUT), 
    // which means you need the Id to know which Choice was updated.
    //public int ChoiceIndex { get; set; }

    public string AnswerText { get; set; }
}

2-您可以像这样在实体和相应的Dto之间创建映射,确保从global.asax文件中调用此代码。

Mapper.CreateMap<MultipleChoiceQuestion, MultipleChoiceQuestionDto>();
Mapper.CreateMap<MultipleChoiceQuestionDto, MultipleChoiceQuestion>()
    .ForMember(m => m.MultipleChoiceQuestionId, e => e.Ignore()); // you force automapper to ignore this property

Mapper.CreateMap<PossibleChoice, PossibleChoiceDto>();
Mapper.CreateMap<PossibleChoiceDto, PossibleChoice>()
    .ForMember(m => m.MultipleChoiceQuestion, e => e.Ignore()) //
    .ForMember(m => m.MultipleChoiceQuestionId, e => e.Ignore())
    .ForMember(m => m.ChoiceIndex, e => e.Ignore());

3-在你的controller.Post你需要从DTO映射到实体并将映射的实体保存到数据库。

现在,上面的解决方案适用于POST,但是,您需要考虑PUT场景,很快就会意识到您需要将ID包含在DTO中,如果您决定这样做,那么您需要重新访问第2点中的映射,并删除您决定包含在DTO中的属性的忽略代码。

希望有所帮助。