P30 整体更新/替换资源 PUT
更新是分为两个方式。put:不管你原来对象是啥,就以我当前的对象为主,整体替换成我当前的这个对象。
还需要一个整体替换的对象的参数EmployeeUpdateDto。直接把addDto里面的参数复制过来。由于它是整体更新 整体替换,如果穿过来的参数没有包含某个字段的话。
那么这个字段就会设置成它的默认值。可以是它类型的默认值,也可以自己设定规则。
传进来的对象如果不包含这俩属性
而且这个Gender枚举类型没有默认值
updateDto里面包含了。ID
但是我们的路由里面也包含了ID。它是以路由参数的形式传进来的。所以在updateDto里面在加上id的话就是多余的信息了。
updateDto和addDto是一样的,为什么我们不使用一个呢?这俩dto干的活是不一样的,它俩只不过暂时是一样的。大部分情况下,它俩确实不一样。
controller的action上我们就加上这个updateDto
如果验证有问题,会自动返回422的状态码。
我们需要手动检查companyId和employeeId分别对应的id是否存在。这两块的代码提前写好,直接贴进来。
整体更新/替换
autoMapper一句话就把上面三个步骤全部做完了。
还需要配置摄影,从updateDto到entity
这里employee映射到Entity之后,这个Entity就包含了需要更新的一些值了。
调用更新的方法
进入到这个方法,实际上我们什么都没写。这个是因为DBcontext Framework Core的事。entity查出来之后,它的属性都是被跟踪 的,一旦它的属性值变化之后,dbContext就知道了。
之后之后一执行saveChanges方法,这些变化就被写入到数据库了。所以这块不写代码也会执行更新。
那么既然什么都不写,我们为什么还要写这个方法呢?因为repository这种模式,它是要求与存储技术无关的,如果我们不使用EF Core来更新代码的话,那么这里更新的操作就有可能需要写一些代码。
为什么使用Repository这种模式?首先他能做到与存储无关,让我们在写Controller的时候只用关心业务逻辑就可以了。repository相当于做了一层抽象。相当于是做了一层合约,让你在写代码的时候只关心这些合约就可以了。
如果你在Controller内直接写EF core的代码的话,你可能就到处重复。到处重复你可能在修改的时候就可以改了这个地方 忘记改另外的地方。容易出错。
repository给你抽象,形成合约之后,这些问题就可以避免。
再就是它有利于单元测试。由于它使用这种IRepository这种接口。
所以之类我们只需要save就可以了
这里就返回一个204 NoContent
所以我们上面返回的类型就是一个IActionResult
测试
准备好的请求
对应的所有字段都写上
如果你不想更新某个字段,那么这个字段原来是什么,你就写上什么。否则就会更新为默认值了。
http://localhost:5000/api/companies/bbdee09c-089b-4d30-bece-44df5923716c/employees/ca268a19-0f39-4d8b-b8d6-5bace54f8027
{ "employeeNo":"MSFT123100", "firstName":"Nick1", "lastName":"Carter1", "gender":1, "dateOfBirth":"1980-12-24" }
都是json类型。
Content-Type:application/json
Accept:application/json
application/json
发送请求有个断点 发生错误
updateDto 自定义的attribute验证 去掉
再次运行程序,测试。请求成功 返回204.
http://localhost:5000/api/companies/bbdee09c-089b-4d30-bece-44df5923716c/employees/ca268a19-0f39-4d8b-b8d6-5bace54f8027
查询下这个资源:同样的链接地址,换成GET请求就是查询:
http://localhost:5000/api/companies/bbdee09c-089b-4d30-bece-44df5923716c/employees/ca268a19-0f39-4d8b-b8d6-5bace54f8027
复制上面的id和companyId 然后到put请求内。然后把结尾改成00结尾的。
结果仍然是204
在查询一下。id和companyId没有受影响被更新。因为我们的updateDto并不包含这两个属性。所以传进来的这两个多余的属性,直接被忽略掉了
把验证相关的代码先都注释掉
在数据内,这三个字段都必填的,如果这里不传入firstName和lastName
就留一个属性
发送请求,引起了错误
这俩字段没有要求必填
这个时候成功了
枚举的gender变成了默认值0。0没有对应任何一个值
日期肯定变成了 0001年 也是datetime的默认值。 所以才是2019岁。
所以put必须要把所有的值都写上,如果不想改它原来的值,那么就把原来的值传过来。
put action是有副作用的。
不是安全的。发送一个put请求和发送多次他们的副作用都是一样的
再把验证信息都加回来
实际上addDto和updateDto他们的验证也没必要是一样的。多数情况下 多少还是有些区别的。这里做的demo比较简单,所以是一样的。
抽象dto类
如果想要减少重复的代码的话,那么就提取一个抽象类
里面的类复制addDto的所有代码,改个名字,然后加上abstract设置为抽象类。
addDto继承这个抽象类。
updateDto也继承
区别的地方
自定义的attribute这里用的是addDto
由于这个自定义的Attribtue里面了。 updateDto也相当于用了这个自定义的attribute
为了防止不出错,这里我们改成addOrUpdateDto
这两个地方都改下
如果EmployeeNo在addDto是必填的,而在updateDto内不是必填的。
前面加上abstract,让add和UpdateDto分别来实现这个属性。
抽象类和抽象属性
https://blog.csdn.net/qq_44034384/article/details/106654058
测试修改后接口是否还能用
post请求测试。
作业
枚举和Datetime怎么输入验证。枚举只接受1和2这两个整型。
目前gender输入0 暂时能过去
datetime如果不填就超出范围了
结束