automapper unflatten 从父对象中排除值

automapper unflatten excludes value from parent object

当我更新子项 table 中的行时,我遇到了 entity framework 核心 (2.0) 正在对父项 table 执行额外工作的情况。我已将原因确定为未在 AutoMapper 生成的未展平对象树中设置值(我并不是说这是 AutoMapper 中的错误;这可能与我的代码有关)。

我在 API 开发方面使用 ASP.NET Core 2.0、C#、EF Core 2.0 和 AutoMapper。数据库已经存在并且 EF 类 从它搭建了脚手架。

为了简短起见,子 table 是 Note,父 table 是 NoteType。 EF 类(删除无关的列)如下:

//Entity classes
public partial class Note
    {
        public int NoteBookId { get; set; }
        public short NoteSeqNo { get; set; }
        public short NoteTypeId { get; set; }
        public string NoteText { get; set; }

        public NoteBook NoteBook { get; set; }
        public NoteType NoteType { get; set; }
    }

public partial class NoteType
    {
        public NoteType() { Note = new HashSet<Note>(); }
        public short NoteTypeId { get; set; }
        public string NoteTypeDesc { get; set; }
        public ICollection<Note> Note { get; set; }
    }

//DTO class
    public class NoteDto
    {
        public int NoteBookId { get; set; }
        public short NoteSeqNo { get; set; }
        public short NoteTypeId { get; set; }
        public string NoteTypeNoteTypeDesc { get; set; }
        public string NoteText { get; set; }
    }

 public class NoteTypeDto
    {
        public short NoteTypeId { get; set; }
        public string NoteTypeDesc { get; set; }
    }

配置

这是 AutoMapper 配置:

// config in startup.cs
config.CreateMap<Note,NoteDto>().ReverseMap();
config.CreateMap<NoteType,NoteTypeDto>().ReverseMap();

读取数据

作为数据检索的结果,我得到了预期的结果,并且填充了父注释类型描述。

// EF get note in repository
            return await _dbcontext.Note
                .Where(n => n.NoteId == noteId && n.NoteSeqNo == noteSeqNo)
                .Include(n => n.NoteType)
                .FirstOrDefaultAsync();

// Get note function in API controller
                Note note = await _repository.GetNoteAsync(id, seq);
                NoteDto noteDto = Mapper.Map<NoteDto>(note);

示例 JSON 结果:

{
    "noteBookId": 29,
    "noteSeqNo": 19,
    "noteTypeId": 18,
    "noteTypenoteTypeDesc": "ABCDE",
    "noteText": "My notes here."
}

更新数据

在更新期间反转过程时,API 控制器将 dto 映射到实体

Mapper.Map<Note>(noteDto)

然后当它被存储库代码传递给 EF 时,EF 尝试添加一个 id 为 0 的 NoteType 行。未展开的对象树如下所示:

Note
    NoteBookId = 29
    NoteSeqNo = 19
    NoteTypeId = 18
    NoteTypeNoteTypeDesc = "ABCDE"
    NoteText = "My notes updated."
    NoteType.NoteTypeDesc = "ABCDE"
    NoteType.NoteTypeId = 0

父 ID 列 (NoteType.NoteTypeId) 的值为 0,未分配到我预期的值 18。

(在调试期间,我手动将 NoteType.NoteTypeId 设置为 18 以确保 EF 不对其进行任何操作)。

为了解决这个问题,我在存储库代码中取消了 Note 中的 NoteType。

我应该期望 AutoMapper 使用 setter 填充所有父属性还是我错过了一些配置?也许我的方法有明显的缺陷?

MapFrom-s(包括默认的展开)are reversed now。您可以删除 ReverseMap 并创建地图,忽略 Note.NoteType 或忽略有问题的路径 Note.NoteType.NoteTypeDesc.

当AutoMapper 反转映射时,它必须从平面对象中收集嵌套对象的所有信息。您的 DTO 仅包含映射 NoteType -> NoteTypeDesc 的值。不适用于 NoteType -> NoteTypeId,所以 AM 真的不知道从哪里获取该值。

如果你只想依赖扁平化,改变它的唯一方法是在 DTO 中添加一个扁平化的 NoteTypeId 除了未扁平化的之外:

public class NoteDto
{
    public int NoteBookId { get; set; }
    public short NoteSeqNo { get; set; }
    public short NoteTypeId { get; set; } // Not flattened
    public short NoteTypeNoteTypeId { get; set; } // Flattened
    public string NoteTypeNoteTypeDesc { get; set; }
    public string NoteText { get; set; }
}

另一种方法是将其添加到您的映射中:

config.CreateMap<Note, NoteDto>()
    .ForMember(dest => dest.NoteTypeId,
        e => e.MapFrom(src => src.NoteType.NoteTypeId))
    .ReverseMap();