我正在使用AutoMapper在我的DTO和业务对象之间进行映射。这很好。
但是,我有一个Web API,它接受PUT请求以更新实体。行动如下:
public virtual async Task<IHttpActionResult> Put(string id, [FromBody] ProjectDto projectDto)
从ProjectDto映射到Project(业务对象)时,它映射ProjectDto中的所有值。假设我想通过向API发送以下JSON来更新项目的名称:
{
"projectId": 10,
"name": "The new name"
}
由于我没有给ProjectDto的所有其他属性赋值,AutoMapper会映射我没有提供值的默认值。
例如,如果ProjectDto有几个额外的字段,它们现在将为null:
{
"projectId": 10,
"name": "The new name",
"createdDate": null,
"manager": null
}
...等。
我的映射如下所示:
cfg.CreateMap<ProjecDto, Project>()
.ForAllMembers(opt => opt.Condition(x => x != null));
..但AutoMapper仍在映射空值。
我查看了this question,但是当我尝试复制他们的解决方案时,我得到“ProjectDto不包含IsSourceValueNull的定义”。
Web API控制器操作(它是通用的,TDto是一个空的标记接口.T和TDto分别在运行时解析为Project和ProjectDto。):
public virtual async Task<IHttpActionResult> Put(string id, [FromBody] TDto model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = _dataContext.GetRepository<T>().GetById(id);
if (entity == null)
return NotFound();
var entityToUpdate = _mapper.Map<T>(model);
var updatedEntity = _dataContext.GetRepository<T>().Update(entity);
var updatedEntityDto = _mapper.Map<TDto>(updatedEntity);
return Ok(updatedEntityDto);
}
答案 0 :(得分:0)
从根本上说它应该是这样的,你需要将完整的对象与更改的值放在一起。 PUT期望按照REST标准(api / project)完整对象 - 而不是部分或脏对象。
如果您想要更新特定属性,请使用不同的终点,例如
api/project/prop1
api/project/prop2
然后将相关值添加到它们。
如果要覆盖此行为,请编写自己的映射以放置这些条件。
请在auto-mapper中使用null替换功能.. https://github.com/AutoMapper/AutoMapper/wiki/Null-substitution
选项:2(可能是Hack)
cfg.CreateMap<ProjecDto, Project>();
cfg.CreateMap<Project, Project>()
.ForAllMembers(opt => opt.Condition(x => x != null));
和API
public virtual async Task<IHttpActionResult> Put(string id, [FromBody] TDto model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = _dataContext.GetRepository<T>().GetById(id);
if (entity == null)
return NotFound();
var entityToUpdate = _mapper.Map<T>(model);
entityToUpdate = _mapper.Map<T, T>(entityToUpdate, entity); // overwriting the db object with new vals, may be swap around it, I haven't tested.
var updatedEntity = _dataContext.GetRepository<T>().Update(entityToUpdate);
var updatedEntityDto = _mapper.Map<TDto>(updatedEntity);
return Ok(updatedEntityDto);
}