automapper unflatten从父对象

时间:2017-10-04 14:10:15

标签: repository automapper entity-framework-core dto

我有一种情况,当我更新子表中的行时,实体框架核心(2.0)正在对父表执行额外的工作。我已经将原因指向了一个没有在AutoMapper生成的unflattened对象树中设置的值(我不是说它在AutoMapper中是一个错误;它可能更多地与我的代码有关)。

我在API开发方面使用ASP.NET Core 2.0,C#,EF Core 2.0和AutoMapper。数据库已经存在,并且EF类从中支持。

为了简短起见,子表是Note,父表是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; }
    }
  • (NoteBookId + NoteSeqNo)是Note的主键。
  • NoteTypeId是NoteType的主键。

配置

这是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不对其执行任何操作)。

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

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

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

当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();