Asp.net 带POST请求的AutoMapper的实际使用

Asp.net 带POST请求的AutoMapper的实际使用,asp.net,entity-framework,automapper,dto,Asp.net,Entity Framework,Automapper,Dto,在GET请求中,我可以使用AutoMapper轻松创建从后端模型到定制DTO的映射。但是,在使用AutoMapper和POST请求时,我有一些顾虑 假设一个用户在线订购一个产品,他向服务器发送一个带有一些必需数据的POST请求。事实上,并非后端模型中的所有数据都是由用户发送的。假设Order的ID是一个GUID,当条目插入数据库时自动生成;或者可能还有其他自动递增的属性。所有这些无法映射的属性都会导致大量.ForMember(dest=>dest.myProperty,opt=>opt.Igno

GET
请求中,我可以使用
AutoMapper
轻松创建从后端模型到定制DTO的映射。但是,在使用
AutoMapper
POST
请求时,我有一些顾虑

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

AutoMapper
是否不是为上述场景而设计的?如果后端模型比DTO复杂得多,那么处理模型映射过程的实践是什么


使现代化 此阶段缺少的属性:

  • 多回音
    • 插入后生成
  • 精选指数
    • 从1自动递增到可用答案数

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

我不确定您在体系结构中的何处使用AutoMapper,但是您可以在进行自动映射之前在概念上列出属性。例如,如果您在MVC中进行modelbinding,那么有一些技术(例如在UpdateModel方法中)可以包括或排除属性列表

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; }
}
public class multiplechicequestiondto
{
//此属性可以保留在这里,因为您可能需要使用相同的DTO进行更新(PUT),
//这意味着您需要Id来根据URL Id区分和验证DTO数据
//公共Guid MultipleChoiceQuestionId{get;set;}
公共字符串问题{get;set;}
公共ICollection-PossibleChoices{get;set;}
}
可能的公共类EchoicedTo
{
//这可以从这个dto开始,因为这个dto是其父dto的子dto。
//公共Guid MultipleChoiceQuestionId{get;set;}
//此属性可以保留在这里,因为您可能需要使用相同的DTO进行更新(PUT),
//这意味着您需要Id来知道更新了哪个选项。
//public int ChoiceIndex{get;set;}
公共字符串应答文本{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());
Mapper.CreateMap();
Mapper.CreateMap()
.ForMember(m=>m.MultipleChoiceQuestionId,e=>e.Ignore());//您强制automapper忽略此属性
CreateMap();
Mapper.CreateMap()
.ForMember(m=>m.MultipleChoiceQuestion,e=>e.Ignore())//
.ForMember(m=>m.MultipleChoiceQuestionId,e=>e.Ignore())
.ForMember(m=>m.ChoiceIndex,e=>e.Ignore());
3-在控制器中。Post需要从DTO映射到实体,并将映射的实体保存到数据库

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


希望这能有所帮助。

当我遇到类似的情况时,我会将自己对使用自动映射的犹豫解释为一个强烈的迹象,表明涉及的业务逻辑太多,因此转而求助于手动映射。您转向SO的事实可能已经足够了:)在该领域使用mapper插件来处理
insert
请求是否很常见?我通常只使用AutoMapper将其展平到DTO或查看模型。AutoMapper非常适合展平,但不适合复制有效的对象树,该对象树将保留回数据库。Jasen,这正是我想知道的,因为web上的许多文章都指出,
AutoMapper
处理两个方向的映射是绝对可行的,
DTO后端型号
。然而,我发现自己处于问题中提到的情况。目前我正在尝试在
POST
端点中使用
AutoMapper
插入新条目。我发现我的模型中有很多属性无法映射,因为没有数据可以映射。结果是我不得不写一行又一行的
Ignore()
语句,并在经历映射过程后对对象进行后处理。不,我是从你的问题中得到的。我是说,你在哪里?它是在MVC应用程序还是其他web应用程序框架中?如果在MVC中,它是在自定义ModelBinder中,还是在应用程序的其他部分中?我使用的是Web API 2。您应该能够对发布的值使用自定义模型,而这些值不包括您不想映射的内容,那么,否?那么,只需手动从自定义模型映射到后端模型?但如果我从
multipleechoicequestion
中删除
Ignore
代码,则在
POST
阶段(创建新问题)没有
Guid
。我可以做些什么来满足这两个请求操作?然后您将映射Guid的默认值,但在put的情况下,它将是实际的Guid值,允许您将问题或答案映射到数据库中的原始问题。如何在创建新问题时设置默认的
Guid
Guid
数据库生成的
。调用
SaveChanges()
时,将出现运行时错误,指示
主键
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; }
}
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());