{"id":1120,"date":"2025-05-27T14:46:43","date_gmt":"2025-05-27T06:46:43","guid":{"rendered":"https:\/\/www.hyy.net\/?p=1120"},"modified":"2025-05-27T14:46:43","modified_gmt":"2025-05-27T06:46:43","slug":"ultimate-asp-net-core-web-api-11-working-with-put-requests","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=1120","title":{"rendered":"Ultimate ASP.NET Core Web API 11 WORKING WITH PUT REQUESTS"},"content":{"rendered":"<p>11 WORKING WITH PUT REQUESTS<br \/>\n11 \u4f7f\u7528 PUT \u8bf7\u6c42<\/p>\n<p>In this section, we are going to show you how to update a resource using the PUT request. We are going to update a child resource first and then we are going to show you how to execute insert while updating a parent resource.\u200c<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u5411\u60a8\u5c55\u793a\u5982\u4f55\u4f7f\u7528 PUT \u8bf7\u6c42\u66f4\u65b0\u8d44\u6e90\u3002\u6211\u4eec\u5c06\u9996\u5148\u66f4\u65b0\u5b50\u8d44\u6e90\uff0c\u7136\u540e\u6211\u4eec\u5c06\u5411\u60a8\u5c55\u793a\u5982\u4f55\u5728\u66f4\u65b0\u7236\u8d44\u6e90\u65f6\u6267\u884c insert\u3002<\/p>\n<h2>11.1 Updating Employee<\/h2>\n<p>11.1 \u66f4\u65b0\u5458\u5de5<\/p>\n<p>In the previous sections, we first changed our interface, then the repository\/service classes, and finally the controller. But for the update, this doesn\u2019t have to be the case.\u200c<br \/>\n\u5728\u524d\u9762\u7684\u90e8\u5206\u4e2d\uff0c\u6211\u4eec\u9996\u5148\u66f4\u6539\u4e86\u63a5\u53e3\uff0c\u7136\u540e\u66f4\u6539\u4e86\u5b58\u50a8\u5e93\/\u670d\u52a1\u7c7b\uff0c\u6700\u540e\u66f4\u6539\u4e86\u63a7\u5236\u5668\u3002\u4f46\u5bf9\u4e8e\u66f4\u65b0\uff0c\u60c5\u51b5\u5e76\u975e\u5fc5\u987b\u5982\u6b64\u3002<\/p>\n<p>Let\u2019s go step by step.<br \/>\n\u8ba9\u6211\u4eec\u4e00\u6b65\u4e00\u6b65\u6765\u3002<\/p>\n<p>The first thing we are going to do is to create another DTO record for update purposes:<br \/>\n\u6211\u4eec\u8981\u505a\u7684\u7b2c\u4e00\u4ef6\u4e8b\u662f\u521b\u5efa\u53e6\u4e00\u4e2a DTO \u8bb0\u5f55\u4ee5\u8fdb\u884c\u66f4\u65b0\uff1a<\/p>\n<pre><code>public record EmployeeForUpdateDto(string Name, int Age, string Position);<\/code><\/pre>\n<p>We do not require the Id property because it will be accepted through the URI, like with the DELETE requests. Additionally, this DTO contains the same properties as the DTO for creation, but there is a conceptual difference between those two DTO classes. One is for updating and the other is for creating. Furthermore, once we get to the validation part, we will understand the additional difference between those two.<br \/>\n\u6211\u4eec\u4e0d\u9700\u8981 Id \u5c5e\u6027\uff0c\u56e0\u4e3a\u5b83\u5c06\u901a\u8fc7 URI \u63a5\u53d7\uff0c\u5c31\u50cf DELETE \u8bf7\u6c42\u4e00\u6837\u3002\u6b64\u5916\uff0c\u6b64 DTO \u5305\u542b\u4e0e\u7528\u4e8e\u521b\u5efa\u7684 DTO \u76f8\u540c\u7684\u5c5e\u6027\uff0c\u4f46\u8fd9\u4e24\u4e2a DTO \u7c7b\u4e4b\u95f4\u5b58\u5728\u6982\u5ff5\u5dee\u5f02\u3002\u4e00\u4e2a\u7528\u4e8e\u66f4\u65b0\uff0c\u53e6\u4e00\u4e2a\u7528\u4e8e\u521b\u5efa\u3002\u6b64\u5916\uff0c\u4e00\u65e6\u6211\u4eec\u8fdb\u5165\u9a8c\u8bc1\u90e8\u5206\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u8fd9\u4e24\u8005\u4e4b\u95f4\u7684\u989d\u5916\u533a\u522b\u3002<\/p>\n<p>Because we have an additional DTO record, we require an additional mapping rule:<br \/>\n\u56e0\u4e3a\u6211\u4eec\u6709\u989d\u5916\u7684 DTO \u8bb0\u5f55\uff0c\u6240\u4ee5\u6211\u4eec\u9700\u8981\u989d\u5916\u7684\u6620\u5c04\u89c4\u5219\uff1a<\/p>\n<pre><code>CreateMap&lt;EmployeeForUpdateDto, Employee&gt;();<\/code><\/pre>\n<p>After adding the mapping rule, we can modify the IEmployeeService interface:<br \/>\n\u6dfb\u52a0\u6620\u5c04\u89c4\u5219\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u4fee\u6539 IEmployeeService \u63a5\u53e3\uff1a<\/p>\n<pre><code>using Shared.DataTransferObjects;\n\nnamespace Service.Contracts\n{\n    public interface IEmployeeService\n    {\n        IEnumerable&lt;EmployeeDto&gt; GetEmployees(Guid companyId, bool trackChanges);\n        EmployeeDto GetEmployee(Guid companyId, Guid id, bool trackChanges);\n        EmployeeDto CreateEmployeeForCompany(Guid companyId, EmployeeForCreationDto employeeForCreation, bool trackChanges);\n        void DeleteEmployeeForCompany(Guid companyId, Guid id, bool trackChanges);\n        void UpdateEmployeeForCompany(Guid companyId, Guid id, EmployeeForUpdateDto employeeForUpdate, bool compTrackChanges, bool empTrackChanges);\n    }\n}<\/code><\/pre>\n<p>We are declaring a method that contains both id parameters \u2013 one for the company and one for employee, the employeeForUpdate object sent from the client, and two track changes parameters, again, one for the company and one for the employee. We are doing that because we won't track changes while fetching the company entity, but we will track changes while fetching the employee.<br \/>\n\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a id \u53c2\u6570\u7684\u65b9\u6cd5 \u2013 \u4e00\u4e2a\u7528\u4e8e\u516c\u53f8\uff0c\u4e00\u4e2a\u7528\u4e8e\u5458\u5de5\uff0c\u4ece\u5ba2\u6237\u7aef\u53d1\u9001\u7684 employeeForUpdate \u5bf9\u8c61\uff0c\u4ee5\u53ca\u4e24\u4e2a\u8ddf\u8e2a\u66f4\u6539\u53c2\u6570\uff0c\u540c\u6837\uff0c\u4e00\u4e2a\u7528\u4e8e\u516c\u53f8\uff0c\u4e00\u4e2a\u7528\u4e8e\u5458\u5de5\u3002\u6211\u4eec\u8fd9\u6837\u505a\u662f\u56e0\u4e3a\u6211\u4eec\u4e0d\u4f1a\u5728\u83b7\u53d6\u516c\u53f8\u5b9e\u4f53\u65f6\u8ddf\u8e2a\u66f4\u6539\uff0c\u4f46\u6211\u4eec\u4f1a\u5728\u83b7\u53d6\u5458\u5de5\u65f6\u8ddf\u8e2a\u66f4\u6539\u3002<\/p>\n<p>That said, let\u2019s modify the EmployeeService class:<br \/>\n\u4e5f\u5c31\u662f\u8bf4\uff0c\u8ba9\u6211\u4eec\u4fee\u6539 EmployeeService \u7c7b\uff1a<\/p>\n<pre><code>public void UpdateEmployeeForCompany(Guid companyId, Guid id, EmployeeForUpdateDto employeeForUpdate, bool compTrackChanges, bool empTrackChanges)\n{\n    var company = _repository.Company.GetCompany(companyId, compTrackChanges);\n    if (company is null)\n        throw new CompanyNotFoundException(companyId);\n    var employeeEntity = _repository.Employee.GetEmployee(companyId, id, empTrackChanges);\n    if (employeeEntity is null)\n        throw new EmployeeNotFoundException(id);\n    _mapper.Map(employeeForUpdate, employeeEntity);\n    _repository.Save();\n}<\/code><\/pre>\n<p>So first, we fetch the company from the database. If it doesn\u2019t exist, we interrupt the flow and send the response to the client. After that, we do the same thing for the employee. But there is one difference here. Pay attention to the way we fetch the company and the way we fetch the employeeEntity. Do you see the difference?<br \/>\n\u56e0\u6b64\uff0c\u9996\u5148\uff0c\u6211\u4eec\u4ece\u6570\u636e\u5e93\u4e2d\u83b7\u53d6\u516c\u53f8\u3002\u5982\u679c\u4e0d\u5b58\u5728\uff0c\u6211\u4eec\u5c06\u4e2d\u65ad\u6d41\u5e76\u5c06\u54cd\u5e94\u53d1\u9001\u5230\u5ba2\u6237\u7aef\u3002\u4e4b\u540e\uff0c\u6211\u4eec\u4e3a\u5458\u5de5\u505a\u540c\u6837\u7684\u4e8b\u60c5\u3002\u4f46\u8fd9\u91cc\u6709\u4e00\u4e2a\u533a\u522b\u3002\u6ce8\u610f\u6211\u4eec\u83b7\u53d6 company \u7684\u65b9\u5f0f\u4ee5\u53ca\u6211\u4eec\u83b7\u53d6 employeeEntity \u7684\u65b9\u5f0f\u3002\u60a8\u770b\u5230\u533a\u522b\u4e86\u5417\uff1f<\/p>\n<p>As we\u2019ve already said: the trackChanges parameter will be set to true for the employeeEntity. That\u2019s because we want EF Core to track changes on this entity. This means that as soon as we change any property in this entity, EF Core will set the state of that entity to Modified.<br \/>\n\u6b63\u5982\u6211\u4eec\u5df2\u7ecf\u8bf4\u8fc7\u7684\uff1aemployeeEntity \u7684 trackChanges \u53c2\u6570\u5c06\u8bbe\u7f6e\u4e3a true\u3002\u8fd9\u662f\u56e0\u4e3a\u6211\u4eec\u5e0c\u671b EF Core \u8ddf\u8e2a\u6b64\u5b9e\u4f53\u4e0a\u7684\u66f4\u6539\u3002\u8fd9\u610f\u5473\u7740\uff0c\u4e00\u65e6\u6211\u4eec\u66f4\u6539\u6b64\u5b9e\u4f53\u4e2d\u7684\u4efb\u4f55\u5c5e\u6027\uff0cEF Core \u5c31\u4f1a\u5c06\u8be5\u5b9e\u4f53\u7684\u72b6\u6001\u8bbe\u7f6e\u4e3a Modified\u3002<\/p>\n<p>As you can see, we are mapping from the employeeForUpdate object (we will change just the age property in a request) to the employeeEntity \u2014 thus changing the state of the employeeEntity object to Modified.<br \/>\n\u5982\u60a8\u6240\u89c1\uff0c\u6211\u4eec\u6b63\u5728\u4ece employeeForUpdate \u5bf9\u8c61\uff08\u6211\u4eec\u53ea\u66f4\u6539\u8bf7\u6c42\u4e2d\u7684 age \u5c5e\u6027\uff09\u6620\u5c04\u5230 employeeEntity\uff0c\u4ece\u800c\u5c06 employeeEntity \u5bf9\u8c61\u7684\u72b6\u6001\u66f4\u6539\u4e3a Modified\u3002<\/p>\n<p>Because our entity has a modified state, it is enough to call the Save method without any additional update actions. As soon as we call the Save method, our entity is going to be updated in the database.<br \/>\n\u7531\u4e8e\u6211\u4eec\u7684\u5b9e\u4f53\u5177\u6709\u5df2\u4fee\u6539\u7684\u72b6\u6001\uff0c\u56e0\u6b64\u8c03\u7528 Save \u65b9\u6cd5\u5c31\u8db3\u591f\u4e86\uff0c\u65e0\u9700\u4efb\u4f55\u5176\u4ed6\u66f4\u65b0\u4f5c\u3002\u8c03\u7528 Save \u65b9\u6cd5\u540e\uff0c\u6211\u4eec\u7684\u5b9e\u4f53\u5c06\u5728\u6570\u636e\u5e93\u4e2d\u66f4\u65b0\u3002<\/p>\n<p>Now, when we have all of these, let\u2019s modify the EmployeesController:<br \/>\n\u73b0\u5728\uff0c\u5f53\u6211\u4eec\u62e5\u6709\u6240\u6709\u8fd9\u4e9b\u65f6\uff0c\u8ba9\u6211\u4eec\u4fee\u6539 EmployeesController\uff1a<\/p>\n<pre><code>[HttpPut(&quot;{id:guid}&quot;)]\npublic IActionResult UpdateEmployeeForCompany(Guid companyId, Guid id, [FromBody] EmployeeForUpdateDto employee)\n{\n    if (employee is null) return BadRequest(&quot;EmployeeForUpdateDto object is null&quot;);\n    _service.EmployeeService.UpdateEmployeeForCompany(companyId, id, employee, compTrackChanges: false, empTrackChanges: true);\n    return NoContent();\n}<\/code><\/pre>\n<p>We are using the PUT attribute with the id parameter to annotate this action. That means that our route for this action is going to be: api\/companies\/{companyId}\/employees\/{id}.<br \/>\n\u6211\u4eec\u4f7f\u7528\u5e26\u6709 id \u53c2\u6570\u7684 PUT \u5c5e\u6027\u6765\u6ce8\u91ca\u6b64\u4f5c\u3002\u8fd9\u610f\u5473\u7740\u6b64\u4f5c\u7684\u8def\u7531\u5c06\u4e3a\uff1aapi\/companies\/{companyId}\/employees\/{id}\u3002<\/p>\n<p>Then, we check if the employee object is null, and if it is, we return a BadRequest response.<br \/>\n\u7136\u540e\uff0c\u6211\u4eec\u68c0\u67e5 employee \u5bf9\u8c61\u662f\u5426\u4e3a null\uff0c\u5982\u679c\u4e3a null\uff0c\u5219\u8fd4\u56de BadRequest \u54cd\u5e94\u3002<\/p>\n<p>After that, we just call the update method from the service layer and pass false for the company track changes and true for the employee track changes.<br \/>\n\u4e4b\u540e\uff0c\u6211\u4eec\u53ea\u9700\u4ece\u670d\u52a1\u5c42\u8c03\u7528 update \u65b9\u6cd5\uff0c\u5e76\u4e3a\u516c\u53f8\u8ddf\u8e2a\u53d8\u5316\u4f20\u9012 false\uff0c\u4e3a\u5458\u5de5\u8ddf\u8e2a\u53d8\u5316\u4f20\u9012 true\u3002<\/p>\n<p>Finally, we return the 204 NoContent status.<br \/>\n\u6700\u540e\uff0c\u6211\u4eec\u8fd4\u56de 204 NoContent \u72b6\u6001\u3002<\/p>\n<p>We can test our action:<br \/>\n\u6211\u4eec\u53ef\u4ee5\u6d4b\u8bd5\u6211\u4eec\u7684\u64cd\u4f5c\uff1a<br \/>\n<a href=\"https:\/\/localhost:5001\/api\/companies\/C9D4C053-49B6-410C-BC78-2D54A9991870\/employees\/80ABBCA8-664D-4B20-B5DE-024705497D4A\">https:\/\/localhost:5001\/api\/companies\/C9D4C053-49B6-410C-BC78-2D54A9991870\/employees\/80ABBCA8-664D-4B20-B5DE-024705497D4A<\/a><\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/1101.jpg\" alt=\"alt text\" \/><\/p>\n<p>And it works; we get the 204 No Content status.<br \/>\n\u5b83\u594f\u6548\u4e86;\u6211\u4eec\u5f97\u5230 204 No Content \u72b6\u6001\u3002<\/p>\n<p>We can check our executed query through EF Core to confirm that only the Age column is updated:<br \/>\n\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 EF Core \u68c0\u67e5\u5df2\u6267\u884c\u7684\u67e5\u8be2\uff0c\u4ee5\u786e\u8ba4\u4ec5\u66f4\u65b0\u4e86 Age \u5217\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/1102.jpg\" alt=\"alt text\" \/><\/p>\n<p>Excellent.<br \/>\n\u975e\u5e38\u597d\u3002<\/p>\n<p>You can send the same request with the invalid company id or employee id. In both cases, you should get a 404 response, which is a valid response to this kind of situation.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u65e0\u6548\u7684\u516c\u53f8 ID \u6216\u5458\u5de5 ID \u53d1\u9001\u76f8\u540c\u7684\u8bf7\u6c42\u3002\u5728\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u90fd\u5e94\u8be5\u5f97\u5230 404 \u54cd\u5e94\uff0c\u8fd9\u662f\u5bf9\u8fd9\u79cd\u60c5\u51b5\u7684\u6709\u6548\u54cd\u5e94\u3002<\/p>\n<p><b>NOTE:<\/b>  We\u2019ve changed only the Age property, but we have sent all the other properties with unchanged values as well. Therefore, Age is only updated in the database. But if we send the object with just the Age property, other properties will be set to their default values and the whole object will be updated \u2014 not just the Age column. That\u2019s because the PUT is a request for a full update. This is very important to know.<br \/>\n\u6ce8\u610f\uff1a\u6211\u4eec\u53ea\u66f4\u6539\u4e86 Age \u5c5e\u6027\uff0c\u4f46\u6211\u4eec\u4e5f\u53d1\u9001\u4e86\u503c\u672a\u66f4\u6539\u7684\u6240\u6709\u5176\u4ed6\u5c5e\u6027\u3002\u56e0\u6b64\uff0c\u4ec5\u5728\u6570\u636e\u5e93\u4e2d\u66f4\u65b0 Age\u3002\u4f46\u662f\uff0c\u5982\u679c\u6211\u4eec\u53ea\u53d1\u9001\u5177\u6709 Age \u5c5e\u6027\u7684\u5bf9\u8c61\uff0c\u5219\u5176\u4ed6\u5c5e\u6027\u5c06\u8bbe\u7f6e\u4e3a\u5176\u9ed8\u8ba4\u503c\uff0c\u5e76\u4e14\u6574\u4e2a\u5bf9\u8c61\u5c06\u66f4\u65b0\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f Age \u5217\u3002\u8fd9\u662f\u56e0\u4e3a PUT \u662f\u5b8c\u5168\u66f4\u65b0\u7684\u8bf7\u6c42\u3002\u4e86\u89e3\u8fd9\u4e00\u70b9\u975e\u5e38\u91cd\u8981\u3002<\/p>\n<h3>11.1.1 About the Update Method from the RepositoryBase Class\u200c<\/h3>\n<p>11.1.1 \u5173\u4e8e RepositoryBase \u7c7b\u4e2d\u7684 Update \u65b9\u6cd5<\/p>\n<p>Right now, you might be asking: \u201cWhy do we have the Update method in the RepositoryBase class if we are not using it?\u201d<br \/>\n\u73b0\u5728\uff0c\u60a8\u53ef\u80fd\u4f1a\u95ee\uff1a\u201c\u5982\u679c\u6211\u4eec\u4e0d\u4f7f\u7528 Update \u65b9\u6cd5\uff0c\u4e3a\u4ec0\u4e48\u6211\u4eec\u5728 RepositoryBase \u7c7b\u4e2d\u6709\u5b83\uff1f<\/p>\n<p>The update action we just executed is a connected update (an update where we use the same context object to fetch the entity and to update it). But sometimes we can work with disconnected updates. This kind of update action uses different context objects to execute fetch and update actions or sometimes we can receive an object from a client with the Id property set as well, so we don\u2019t have to fetch it from the database. In that situation, all we have to do is to inform EF Core to track changes on that entity and to set its state to modified. We can do both actions with the Update method from our RepositoryBase class. So, you see, having that method is crucial as well.<br \/>\n\u6211\u4eec\u521a\u521a\u6267\u884c\u7684\u66f4\u65b0\u4f5c\u662f\u8fde\u63a5\u66f4\u65b0\uff08\u6211\u4eec\u4f7f\u7528\u76f8\u540c\u7684\u4e0a\u4e0b\u6587\u5bf9\u8c61\u6765\u83b7\u53d6\u5b9e\u4f53\u5e76\u66f4\u65b0\u5b83\u7684\u66f4\u65b0\uff09\u3002\u4f46\u6709\u65f6\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u65ad\u5f00\u8fde\u63a5\u7684\u66f4\u65b0\u3002\u8fd9\u79cd\u66f4\u65b0\u4f5c\u4f7f\u7528\u4e0d\u540c\u7684\u4e0a\u4e0b\u6587\u5bf9\u8c61\u6765\u6267\u884c fetch \u548c update\u4f5c\uff0c\u6216\u8005\u6709\u65f6\u6211\u4eec\u4e5f\u53ef\u4ee5\u4ece\u8bbe\u7f6e\u4e86 Id \u5c5e\u6027\u7684\u5ba2\u6237\u7aef\u63a5\u6536\u5bf9\u8c61\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u5fc5\u4ece\u6570\u636e\u5e93\u4e2d\u83b7\u53d6\u5b83\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u53ea\u9700\u901a\u77e5 EF Core \u8ddf\u8e2a\u8be5\u5b9e\u4f53\u7684\u66f4\u6539\uff0c\u5e76\u5c06\u5176\u72b6\u6001\u8bbe\u7f6e\u4e3a modified\u3002\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 RepositoryBase \u7c7b\u4e2d\u7684 Update \u65b9\u6cd5\u6267\u884c\u8fd9\u4e24\u4e2a\u4f5c\u3002\u6240\u4ee5\uff0c\u4f60\u770b\uff0c\u62e5\u6709\u8fd9\u79cd\u65b9\u6cd5\u4e5f\u5f88\u91cd\u8981\u3002<\/p>\n<p>One note, though. If we use the Update method from our repository, even if we change just the Age property, all properties will be updated in the database.<br \/>\n\u4e0d\u8fc7\uff0c\u6709\u4e00\u70b9\u9700\u8981\u6ce8\u610f\u3002\u5982\u679c\u6211\u4eec\u4f7f\u7528\u5b58\u50a8\u5e93\u4e2d\u7684 Update \u65b9\u6cd5\uff0c\u5373\u4f7f\u6211\u4eec\u53ea\u66f4\u6539 Age \u5c5e\u6027\uff0c\u6240\u6709\u5c5e\u6027\u90fd\u5c06\u5728\u6570\u636e\u5e93\u4e2d\u66f4\u65b0\u3002<\/p>\n<h2>11.2 Inserting Resources while Updating One<\/h2>\n<p>11.2 \u5728\u66f4\u65b0\u8d44\u6e90\u65f6\u63d2\u5165\u8d44\u6e90<\/p>\n<p>While updating a parent resource, we can create child resources as well without too much effort. EF Core helps us a lot with that process. Let\u2019s see how.\u200c<br \/>\n\u5728\u66f4\u65b0\u7236\u8d44\u6e90\u65f6\uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u521b\u5efa\u5b50\u8d44\u6e90\uff0c\u800c\u65e0\u9700\u592a\u591a\u5de5\u4f5c\u3002EF Core \u5728\u6b64\u8fc7\u7a0b\u4e2d\u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u5f88\u5927\u5e2e\u52a9\u3002\u8ba9\u6211\u4eec\u770b\u770b\u5982\u4f55\u4f5c\u3002<\/p>\n<p>The first thing we are going to do is to create a DTO record for update:<br \/>\n\u6211\u4eec\u8981\u505a\u7684\u7b2c\u4e00\u4ef6\u4e8b\u662f\u521b\u5efa\u4e00\u4e2a\u7528\u4e8e\u66f4\u65b0\u7684 DTO \u8bb0\u5f55\uff1a<\/p>\n<pre><code>public record CompanyForUpdateDto(string Name, string Address, string Country, IEnumerable&lt;EmployeeForCreationDto&gt; Employees);<\/code><\/pre>\n<p>After this, let\u2019s create a new mapping rule:<br \/>\n\u5728\u6b64\u4e4b\u540e\uff0c\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u6620\u5c04\u89c4\u5219\uff1a<\/p>\n<pre><code>CreateMap&lt;CompanyForUpdateDto, Company&gt;();<\/code><\/pre>\n<p>Then, let\u2019s move on to the interface modification:<br \/>\n\u7136\u540e\uff0c\u8ba9\u6211\u4eec\u7ee7\u7eed\u8fdb\u884c\u63a5\u53e3\u4fee\u6539\uff1a<\/p>\n<pre><code>using Shared.DataTransferObjects;\n\nnamespace Service.Contracts\n{\n    public interface ICompanyService\n    {\n        IEnumerable&lt;CompanyDto&gt; GetAllCompanies(bool trackChanges);\n        CompanyDto GetCompany(Guid companyId, bool trackChanges);\n        CompanyDto CreateCompany(CompanyForCreationDto company);\n        IEnumerable&lt;CompanyDto&gt; GetByIds(IEnumerable&lt;Guid&gt; ids, bool trackChanges);\n        (IEnumerable&lt;CompanyDto&gt; companies, string ids) CreateCompanyCollection(IEnumerable&lt;CompanyForCreationDto&gt; companyCollection);\n        void DeleteCompany(Guid companyId, bool trackChanges);\n        void UpdateCompany(Guid companyid, CompanyForUpdateDto companyForUpdate, bool trackChanges);\n    }\n}\n<\/code><\/pre>\n<p>And of course, the service class modification:<br \/>\n\u5f53\u7136\uff0c\u670d\u52a1\u7c7b\u4fee\u6539\uff1a<\/p>\n<pre><code>public void UpdateCompany(Guid companyId, CompanyForUpdateDto companyForUpdate, bool trackChanges)\n{\n    var companyEntity = _repository.Company.GetCompany(companyId, trackChanges);\n    if (companyEntity is null)\n        throw new CompanyNotFoundException(companyId);\n    _mapper.Map(companyForUpdate, companyEntity);\n    _repository.Save();\n}<\/code><\/pre>\n<p>So again, we fetch our company entity from the database, and if it is null, we just return the NotFound response. But if it\u2019s not null, we map the companyForUpdate DTO to companyEntity and call the Save method.<br \/>\n\u56e0\u6b64\uff0c\u6211\u4eec\u4ece\u6570\u636e\u5e93\u4e2d\u83b7\u53d6\u6211\u4eec\u7684\u516c\u53f8\u5b9e\u4f53\uff0c\u5982\u679c\u5b83\u662f null\uff0c\u6211\u4eec\u53ea\u8fd4\u56de NotFound \u54cd\u5e94\u3002\u4f46\u5982\u679c\u5b83\u4e0d\u4e3a null\uff0c\u6211\u4eec\u5c06 companyForUpdate DTO \u6620\u5c04\u5230 companyEntity \u5e76\u8c03\u7528 Save \u65b9\u6cd5\u3002<\/p>\n<p>Right now, we can modify our controller:<br \/>\n\u73b0\u5728\uff0c\u6211\u4eec\u53ef\u4ee5\u4fee\u6539\u6211\u4eec\u7684\u63a7\u5236\u5668\uff1a<\/p>\n<pre><code>[HttpPut(&quot;{id:guid}&quot;)]\npublic IActionResult UpdateCompany(Guid id, [FromBody] CompanyForUpdateDto company)\n{\n    if (company is null)\n        return BadRequest(&quot;CompanyForUpdateDto object is null&quot;);\n    _service.CompanyService.UpdateCompany(id, company, trackChanges: true);\n    return NoContent();\n}<\/code><\/pre>\n<p>That\u2019s it. You can see that this action is almost the same as the employee update action.<br \/>\n\u5c31\u662f\u8fd9\u6837\u3002\u60a8\u53ef\u4ee5\u770b\u5230\uff0c\u6b64\u4f5c\u4e0e employee update\u4f5c\u51e0\u4e4e\u76f8\u540c\u3002<\/p>\n<p>Let\u2019s test this now:<br \/>\n\u73b0\u5728\u8ba9\u6211\u4eec\u6d4b\u8bd5\u4e00\u4e0b\uff1a<br \/>\n<a href=\"https:\/\/localhost:5001\/api\/companies\/3d490a70-94ce-4d15-9494-5248280c2ce3i\">https:\/\/localhost:5001\/api\/companies\/3d490a70-94ce-4d15-9494-5248280c2ce3i<\/a><\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/1103.jpg\" alt=\"alt text\" \/><\/p>\n<p>We modify the name of the company and attach an employee as well. As a result, we can see 204, which means that the entity has been updated. But what about that new employee?<br \/>\n\u6211\u4eec\u4fee\u6539\u516c\u53f8\u540d\u79f0\u5e76\u9644\u52a0\u5458\u5de5\u3002\u7ed3\u679c\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230 204\uff0c\u8fd9\u610f\u5473\u7740\u8be5\u5b9e\u4f53\u5df2\u66f4\u65b0\u3002\u4f46\u662f\u90a3\u4f4d\u65b0\u5458\u5de5\u5462\uff1f<\/p>\n<p>Let\u2019s inspect our query:<br \/>\n\u6211\u4eec\u6765\u68c0\u67e5\u4e00\u4e0b\u6211\u4eec\u7684\u67e5\u8be2\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/images\/ultimateaspnetcorewebapi6\/1104.jpg\" alt=\"alt text\" \/><\/p>\n<p>You can see that we have created the employee entity in the database. So, EF Core does that job for us because we track the company entity. As soon as mapping occurs, EF Core sets the state for the company entity to modified and for all the employees to added. After we call the Save method, the Name property is going to be modified and the employee entity is going to be created in the database.<br \/>\n\u60a8\u53ef\u4ee5\u770b\u5230\u6211\u4eec\u5df2\u7ecf\u5728\u6570\u636e\u5e93\u4e2d\u521b\u5efa\u4e86 employee \u5b9e\u4f53\u3002\u56e0\u6b64\uff0cEF Core \u4e3a\u6211\u4eec\u5b8c\u6210\u4e86\u8fd9\u9879\u5de5\u4f5c\uff0c\u56e0\u4e3a\u6211\u4eec\u8ddf\u8e2a\u516c\u53f8\u5b9e\u4f53\u3002\u6620\u5c04\u53d1\u751f\u540e\uff0cEF Core \u4f1a\u5c06\u516c\u53f8\u5b9e\u4f53\u7684\u72b6\u6001\u8bbe\u7f6e\u4e3a modified\uff0c\u5e76\u5c06\u6240\u6709\u5458\u5de5\u7684\u72b6\u6001\u8bbe\u7f6e\u4e3a added\u3002\u8c03\u7528 Save \u65b9\u6cd5\u540e\uff0c\u5c06\u4fee\u6539 Name \u5c5e\u6027\uff0c\u5e76\u5728\u6570\u636e\u5e93\u4e2d\u521b\u5efa employee \u5b9e\u4f53\u3002<\/p>\n<p>We are finished with the PUT requests, so let\u2019s continue with PATCH.<br \/>\n\u6211\u4eec\u5df2\u7ecf\u5b8c\u6210\u4e86 PUT \u8bf7\u6c42\uff0c\u6240\u4ee5\u8ba9\u6211\u4eec\u7ee7\u7eed PATCH\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>11 WORKING WITH PUT REQUESTS 11 \u4f7f\u7528 PUT \u8bf7\u6c42 In this section, we are going to show you how to update a resource using the PUT request. We are going to update a child resource first and then we are going to show you how to execute insert while updating a parent resource.\u200c \u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u5411\u60a8\u5c55\u793a\u5982\u4f55\u4f7f\u7528 PUT [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1120","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1120"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1120\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}