【问题标题】:Practical usage of AutoMapper with POST requestAutoMapper 与 POST 请求的实际使用
【发布时间】:2014-12-06 14:58:01
【问题描述】:

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

假设用户在线订购产品,他向服务器发送POST 请求,其中包含一些所需的数据。事实上,并不是后端模型中的每一条数据都是由用户发送的。假设OrderID 是一个GUID,它是在将条目插入数据库时​​自动生成的;或者也许还有其他自动递增的属性。所有这些 cannot-be-mapped 属性会导致大量 .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
    • 插入后生成
  • 选择索引
    • 自动从 1 增加到可用答案的数量

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

【问题讨论】:

  • 当我遇到类似情况时,我将自己对使用自动映射的犹豫解释为涉及太多业务逻辑的强烈指标,因此转而使用手动映射。你转向 SO 的事实可能就足够了:)
  • 在现场使用映射器插件处理insert请求是否常见?
  • 我通常只使用 AutoMapper 来展平 DTO 或查看模型。 AutoMapper 非常适合展平,但不太适合复制将持久化回数据库的有效对象树。
  • Jasen,这正是我想知道的,因为网络上的许多文章指出,AutoMapper 处理两个方向的映射是绝对可行和可行的,DTO &lt;---&gt; back-end model。但是,我发现自己处于我的问题中提到的情况。

标签: asp.net entity-framework automapper dto


【解决方案1】:

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 中的属性的忽略代码。

希望对您有所帮助。

【讨论】:

  • 但是如果我从MultipleChoiceQuestion 中删除Ignore 代码,则POST 阶段不存在Guid(创建一个新问题)。我可以做些什么来满足这两个请求操作?
  • 然后您将映射 Guid 的默认值,但在 put 的情况下,它将是实际的 Guid 值,它允许您将问题或答案映射到数据库中的原始值。
  • 创建新问题时如何设置默认GuidGuidDatabaseGenerated。当我调用SaveChanges() 时,如果您提到的默认值始终具有相同的值,则会出现运行时错误,指示违反了PRIMARY KEY constraint
  • .net 中的每个类型都有一个默认值,可能像对象类型一样为 null,或者像整数一样为 0,所以 Guid 也是如此,所以当 EF 找到分配给 Guid 的默认值时添加了 id 和实体状态,它将在将实体保存到数据库之前生成 Guid 的 id。
  • 我的意思是默认值是当您定义 Guid 变量而不分配任何值时将分配给您的属性的值。你可以调试一下看看。
【解决方案2】:

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

【讨论】:

  • 目前我正在尝试在POST 端点中使用AutoMapper 来插入新条目。我发现我的模型中的许多属性无法映射,因为没有要映射的数据。结果是我必须写一行一行的Ignore()语句,并在经过映射过程后对对象进行后处理。
  • 不,我从你的问题中得知。我的意思是,你在哪里做 AutoMapping?它是在 MVC 应用程序还是其他一些 Web 应用程序框架中?如果在 MVC 中,是在自定义 ModelBinder 中,还是在应用程序的其他部分中?
  • 我正在使用 Web API 2。
  • 您应该可以只对不包含您不想映射的内容的发布值使用自定义模型,不是吗?
  • 那么,只需手动从自定义模型映射到后端模型?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-29
  • 2020-08-27
  • 1970-01-01
  • 2012-10-11
  • 2018-01-31
相关资源
最近更新 更多