是否可以禁止使用 CascadeType 或其他注释替换实体上的现有子实体?
Ιs it possible to disallow replacement of existing children entities on an entity using CascadeType or another annotation?
你好,我正在尝试制作一个 API,它使用这样的实体:
@Entity
@NoArgsConstructor @Getter @Setter
class ParentEntity {
@OneToOne(cascade= {CascadeType.ALL}, orphanRemoval = true)
private ChildEntity child;
}
假设我在 http://localhost:8080/api/v1/parent-entities/1
有一个父实体
我想做的是能够通过以下方式 PUT(更新):
我希望能够即时创建新的子实体,因此需要允许(我想我需要 CascadeType.PERSIST
):
PUT parent-entities/1
{ "child": { "name": "new child" }}
需要允许通过父级更新子级(我想我需要 CascadeType.MERGE
为此)
PUT parent-entities/1
{ "child": { "id": 1, "name": "update existing child name" }}
我还需要能够删除一个项目并将其从数据库中删除(我想我需要 CascadeType.REMOVE
以及 orphanRemoval=true
):
PUT parent-entities/1
{ "child": null} should remove child with id=1 from database
我需要帮助的是不允许允许这个:
PUT parent-entities/1
{ "child": { "id": 2, "name": "other existing child" }}
答案可能与 CascadeType.REFRESH
和 CascadeType.DETACH
或 CascadeType.MERGE
有关
根据我的测试,我无法让它以某种方式工作。我实际上设法销毁了许多现有的 childEntities,使它们的名称等于 null。我最好的猜测是 CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE
Motiviation for the above: Frontend app was sending data for a specific child entity but with wrong id - this had the result to mutate the wrong entity that was completely unrelated and on top of that it was attached to the wrong parent. I still need the CascadeType.MERGE though.
感谢任何帮助!
是的,这可以只用注释来完成。该解决方案最终将向特定列添加可更新字段。
您可以通过删除 CascadeType.MERGE 来阻止更新,但是您也将无法更新 ChildEntity.name... 如果您想阻止特定字段的可更新性,请尝试以下操作。
@Entity
@Getter
@Setter
@NoArgsConstructor
public class ParentEntity implements Serializable {
private static final long serialVersionUID = -3126773862335903987L;
@Id
@GeneratedValue
@Column(updatable = false)
private Long id;
**@JoinColumn(updatable = false)**
@OneToOne(cascade= CascadeType.ALL, orphanRemoval = true)
private ChildEntity child;
}
@Entity
@Getter
@Setter
@NoArgsConstructor
public class ChildEntity implements Serializable {
private static final long serialVersionUID = -2903838577072685774L;
@Id
@GeneratedValue
private Long id;
private String name;
@JsonIgnore
@OneToOne(mappedBy = "child")
private ParentEntity parent;
}
@PutMapping
private ResponseEntity<ParentEntity> update(
@RequestBody final ParentEntity entity) {
return ResponseEntity.of(Optional.of(this.repo.saveAndFlush(entity)));
}
为了演示,请在 application.properties
中启用 show-sql
spring.jpa.show-sql=true
创建初始实体
PUT /parent-entity
{
"child": {
"name": "alpha"
}
}
Hibernate: insert into ChildEntity (name, id) values (?, ?)
Hibernate: insert into ParentEntity (child_id, id) values (?, ?)
PARENT_ID CHILD_ID CHILD NAME
1 2 2 alpha
更新名称
PUT /parent-entity
{
"id": 1,
"child": {
"id": 2,
"name": "beta"
}
}
Hibernate: update ChildEntity set name=? where id=?
PARENT_ID CHILD_ID CHILD NAME
1 2 2 beta
尝试更新 ID
PUT /parent-entity
{
"id": 1,
"child": {
"id": 3,
"name": "gamma"
}
}
{
"timestamp": "2020-01-23T11:08:02.056+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not execute statement; SQL [n/a]; constraint [\"FKGD5S6Q2V5J8MX33JL99EYCY5R: PUBLIC.PARENTENTITY FOREIGN KEY(CHILD_ID) REFERENCES PUBLIC.CHILDENTITY(ID) (2)\"; SQL statement:\ndelete from ChildEntity where id=? [23503-200]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
"path": "/parent-entities"
}
PARENT_ID CHILD_ID CHILD NAME
1 2 2 beta
同样,如果你想防止非引用列被更新,只需使用@Column(updatable = false)
你好,我正在尝试制作一个 API,它使用这样的实体:
@Entity
@NoArgsConstructor @Getter @Setter
class ParentEntity {
@OneToOne(cascade= {CascadeType.ALL}, orphanRemoval = true)
private ChildEntity child;
}
假设我在 http://localhost:8080/api/v1/parent-entities/1
我想做的是能够通过以下方式 PUT(更新):
我希望能够即时创建新的子实体,因此需要允许(我想我需要 CascadeType.PERSIST
):
PUT parent-entities/1
{ "child": { "name": "new child" }}
需要允许通过父级更新子级(我想我需要 CascadeType.MERGE
为此)
PUT parent-entities/1
{ "child": { "id": 1, "name": "update existing child name" }}
我还需要能够删除一个项目并将其从数据库中删除(我想我需要 CascadeType.REMOVE
以及 orphanRemoval=true
):
PUT parent-entities/1
{ "child": null} should remove child with id=1 from database
我需要帮助的是不允许允许这个:
PUT parent-entities/1
{ "child": { "id": 2, "name": "other existing child" }}
答案可能与 CascadeType.REFRESH
和 CascadeType.DETACH
或 CascadeType.MERGE
根据我的测试,我无法让它以某种方式工作。我实际上设法销毁了许多现有的 childEntities,使它们的名称等于 null。我最好的猜测是 CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE
Motiviation for the above: Frontend app was sending data for a specific child entity but with wrong id - this had the result to mutate the wrong entity that was completely unrelated and on top of that it was attached to the wrong parent. I still need the CascadeType.MERGE though.
感谢任何帮助!
是的,这可以只用注释来完成。该解决方案最终将向特定列添加可更新字段。
您可以通过删除 CascadeType.MERGE 来阻止更新,但是您也将无法更新 ChildEntity.name... 如果您想阻止特定字段的可更新性,请尝试以下操作。
@Entity
@Getter
@Setter
@NoArgsConstructor
public class ParentEntity implements Serializable {
private static final long serialVersionUID = -3126773862335903987L;
@Id
@GeneratedValue
@Column(updatable = false)
private Long id;
**@JoinColumn(updatable = false)**
@OneToOne(cascade= CascadeType.ALL, orphanRemoval = true)
private ChildEntity child;
}
@Entity
@Getter
@Setter
@NoArgsConstructor
public class ChildEntity implements Serializable {
private static final long serialVersionUID = -2903838577072685774L;
@Id
@GeneratedValue
private Long id;
private String name;
@JsonIgnore
@OneToOne(mappedBy = "child")
private ParentEntity parent;
}
@PutMapping
private ResponseEntity<ParentEntity> update(
@RequestBody final ParentEntity entity) {
return ResponseEntity.of(Optional.of(this.repo.saveAndFlush(entity)));
}
为了演示,请在 application.properties
中启用 show-sqlspring.jpa.show-sql=true
创建初始实体
PUT /parent-entity
{
"child": {
"name": "alpha"
}
}
Hibernate: insert into ChildEntity (name, id) values (?, ?)
Hibernate: insert into ParentEntity (child_id, id) values (?, ?)
PARENT_ID CHILD_ID CHILD NAME
1 2 2 alpha
更新名称
PUT /parent-entity
{
"id": 1,
"child": {
"id": 2,
"name": "beta"
}
}
Hibernate: update ChildEntity set name=? where id=?
PARENT_ID CHILD_ID CHILD NAME
1 2 2 beta
尝试更新 ID
PUT /parent-entity
{
"id": 1,
"child": {
"id": 3,
"name": "gamma"
}
}
{
"timestamp": "2020-01-23T11:08:02.056+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not execute statement; SQL [n/a]; constraint [\"FKGD5S6Q2V5J8MX33JL99EYCY5R: PUBLIC.PARENTENTITY FOREIGN KEY(CHILD_ID) REFERENCES PUBLIC.CHILDENTITY(ID) (2)\"; SQL statement:\ndelete from ChildEntity where id=? [23503-200]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
"path": "/parent-entities"
}
PARENT_ID CHILD_ID CHILD NAME
1 2 2 beta
同样,如果你想防止非引用列被更新,只需使用@Column(updatable = false)