我已经使用PUT/POST来更新我正在使用的应用程序,到目前为止,这一直很简单。现在我正在开发一个API,它应该公开一种更新数据库中数据的方法,我最初的想法是可以替换行(或部分替换行(。由于具有不同数据知识的不同应用程序需要更新,我认为使用PATCH操作而不是PUT是个好主意。
我可以找到一些在控制器中实现更新的玩具示例,我对此不感兴趣
我使用了与jasontaylordev的Clean架构项目中相同的模式(CQRS w.Mediator(,所以我将在我的示例中使用它。
我有两个问题。
-
我不喜欢
JsonPatchDocument
对象应该到达我的Handlers,但我不知道如何避免这种情况。不能从控制器访问数据库。那么还有其他选择吗?(注意:在我正在进行的项目中,Automapper或类似的动态映射库都不是选项( -
如何从客户端应用程序(所有dotnet核心项目(构建JsonPatch对象。我认为如果我可以在应用程序一中有一个DTO,它具有两个属性
Title
和Note
,如果是Title="test"
和Note=null
,那么它应该替换标题并删除注释,这可能会很好。我可以简单地映射到(奇怪的(补丁对象吗?[HttpPatch("{id}")] public async Task<ActionResult> Update(int id, UpdateTodoItemCommand command) { if (id != command.Id) { return BadRequest(); } await Mediator.Send(command); return NoContent(); } public class UpdateTodoItemCommand : IRequest { public int Id { get; set; } public JsonPatchDocument<TodoItemDto> Todo { get; set; } } public class TodoItemDto { public string Title { get; set; } public string Note { get; set; } } public class UpdateTodoItemCommandHandler : IRequestHandler<UpdateTodoItemCommand> { private readonly IApplicationDbContext _context; public UpdateTodoItemCommandHandler(IApplicationDbContext context) { _context = context; } public async Task<Unit> Handle(UpdateTodoItemCommand request, CancellationToken cancellationToken) { var entity = await _context.TodoItems.FindAsync(request.Id); if (entity == null) { throw new NotFoundException(nameof(TodoItem), request.Id); } var todoItemDto = new TodoItemDto(); todoItemDto.Title = entity.Title; todoItemDto.Note = entity.Note: todoItemDto.Todo.ApplyTo(request.Todo); entity.Title = todoItemDto.Title; entity.Note = todoItemDto.Note; await _context.SaveChangesAsync(cancellationToken); return Unit.Value; } }
我遇到了同样的问题,我想出了一个适合我的解决方案。
在UpdateTodoItemCommandHandler类的Handle方法中,您将再创建一个JsonPatchDocument,但类型为TodoItem(而不是Dto(。然后将操作和ContractResolver转移到新的JsonPatchDocument对象,您可以对其进行修补并将其保存到数据库中。类似这样的东西:
var entity = await _context.TodoItems.FindAsync(request.Id); if (entity == null) { throw new NotFoundException(nameof(TodoItem), request.Id); } var todoItemPatch = new JsonPatchDocument<TodoItem>(); foreach (var opr in request.Todo.Operations) { todoItemPatch.Operations.Add(new Operation<TodoItem> { op = opr.op, path = opr.path, value = opr.value }); } todoItemPatch.ContractResolver = request.Todo.ContractResolver; todoItemPatch.ApplyTo(entity); await _context.SaveChangesAsync(cancellationToken);
- 创建自己的类(例如UpdateCommand,它本身与补丁文档非常相似;使用"replace"、"delete"等指令
- 将修补程序文档映射到此类的实例,并通过Mediator进行路由
- 重新创建asp.net工具箱中已经提供的"修补机制">
这似乎需要做很多事情来避免仅仅引用该引用。如果您愿意,您也许可以创建一个保存文档的命令,但这并没有多大作用。
我创建的一个实现只需要获取JsonPatchDocument并将其传递给一个应用补丁的策略类(该策略类与Mediator扮演着相同的角色,因此实际上是相同的东西。然后我对该资源调用了Apply((方法。