我有一种情况,当我更新子表中的行时,实体框架核心(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; }
}
配置
这是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填充所有父属性还是我错过了一些配置?也许我的方法有一个明显的缺陷?
答案 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();