Java 如何防止Hibernate在PUT web请求中将列值更新为null?
我在我的spring boot应用程序上实现CRUD操作,我一直在实现PUT http请求来更新实体的某些值。特别是我的问题是,我的update方法会更新实体中的所有字段,而不管这些值是否为Java 如何防止Hibernate在PUT web请求中将列值更新为null?,java,spring,hibernate,jpa,jackson,Java,Spring,Hibernate,Jpa,Jackson,我在我的spring boot应用程序上实现CRUD操作,我一直在实现PUT http请求来更新实体的某些值。特别是我的问题是,我的update方法会更新实体中的所有字段,而不管这些值是否为null。我在GitHub上查看了无数做同样事情的项目,但考虑到我的实体是复杂类型的,因为它们包含像@OneToMany/@OneToOne这样的关系,我无法找出最好的解决方案 这是我的实体类: @Entity @Table(name = "doctor") @JsonIdentityIn
null
。我在GitHub上查看了无数做同样事情的项目,但考虑到我的实体是复杂类型的,因为它们包含像@OneToMany/@OneToOne这样的关系,我无法找出最好的解决方案
这是我的实体类:
@Entity
@Table(name = "doctor")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Long.class)
@DynamicUpdate(value = true)
public class DoctorProfile implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 10)
private String gender;
@NotNull
@Column(unique = true, name = "phone_number", length = 15)
private String phoneNumber;
@Column(name = "specialization", length = 15)
private String specialization;
@Column(name = "avatar", length = 200)
private String avatar;
@OneToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "doctor_id", nullable = false)
private Doctor doctor;
@OneToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "clinic_id", nullable = false)
@JsonBackReference
private Clinic clinic;
//Getter-Setters omitted
}
这是我的服务课:
public ResponseEntity<DoctorProfile> updateDoctorProfile(DoctorProfile newInfo, long id){
DoctorProfile dc = doctorProfileRepository.findById(id).orElseThrow(
() -> new DoctorNotFoundException(id));
dc.setGender(newInfo.getGender());
dc.setPhoneNumber(newInfo.getPhoneNumber());
dc.setSpecialization(newInfo.getSpecialization());
dc.setClinic(newInfo.getClinic());
dc.setAvatar(newInfo.getAvatar());
final DoctorProfile updatedDoctor = doctorProfileRepository.save(dc);
return ResponseEntity.ok(updatedDoctor);
}
public ResponseEntity updateDoctorProfile(DoctorProfile新信息,长id){
DoctorProfile dc=doctorProfileRepository.findById(id).orelsetrow(
()->新DoctorNotFoundException(id));
setGender(newInfo.getGender());
dc.setPhoneNumber(newInfo.getPhoneNumber());
dc.setSpecialization(newInfo.getSpecialization());
setClinic(newInfo.getClinic());
setAvatar(newInfo.getAvatar());
最终DoctorProfile updatedDoctor=doctorProfileRepository.save(dc);
返回ResponseEntity.ok(updatedDoctor);
}
[@RestController
省略类]
正如您所看到的,我尝试使用@DynamicUpdate注释,该注释应该保持@RequestBody
中null
的所有字段不变,但这对我不起作用
我还考虑实现一个逻辑,检查@RequestBody中的字段是否为null,并最终替换它们,从我试图更新的实体复制值。但这种解决方案有两个问题:
•代码看起来很脏;
•我无法通过@RequestBody
更新@OneToOne等关系引用的值,比如我的@Entity
中的Clinic或Doctor字段,因为我传递的不是整个类,而是ID,虽然这种方法在mysql上有效,但在Spring JPA上无效(我仍在试图找到解决方案)
我在这里读了一些关于堆栈溢出的答案,一些人建议创建一次只更新一个字段的方法,因为HTTP.PUT请求应该是这样工作的。但这真的是一个好方法吗?如果我有100200个甚至更多的列呢?对我来说似乎不切实际和重复。你会有100-200列吗?有时可以逐个字段进行更新 此外,您还可以对信息进行分组,例如,
updatePersonalInformation
,并在其中放置多个字段,或者每个实体只更新一次,这样就可以更新DoctorProfile、Doctor、Clinic
另外,您是否考虑过使用单独的类进行更新,例如
DoctorProfileDto
,它只包含您真正想要更新的信息,这样,您就不会发现自己处于一种情况,即您认为自己有一些值,但它总是空的。首先,PUT应该替换资源,因此,所有传递的状态都应该设置为与预期的语义匹配。您需要的是HTTP补丁
如果要使用它,必须首先加载实体,然后将JSON负载反序列化到该实体上。然后可以使用动态更新或不使用动态更新刷新该实体
我认为这是一个完美的用例,它提供了您想要的语义
我创建了这个库,以便在JPA模型和自定义接口或抽象类定义的模型之间进行简单的映射,类似于类固醇上的Spring数据投影。其思想是以您喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(getter)映射到实体模型
在Blaze持久性实体视图中,您的用例的DTO模型可能如下所示:
@UpdatableEntityView
@EntityView(DoctorProfile.class)
public interface DoctorProfileDto {
@IdMapping
Long getId();
String getGender();
void setGender(String gender);
String getPhoneNumber();
void setPhoneNumber(String phoneNumber);
String getSpecialization();
void setSpecialization(String specialization);
String getAvatar();
void setAvatar(String avatar);
}
查询是将实体视图应用于查询的问题,最简单的就是按id进行查询
DoctorProfileDto a=entityViewManager.find(entityManager,DoctorProfileDto.class,id)代码>
Spring数据集成允许您像使用Spring数据投影一样使用它:
下面是一个示例,说明了这可能是什么样子: