【发布时间】:2020-12-03 22:14:11
【问题描述】:
我正在使用 Spring Data JPA 和 Spring Data Rest。 发出 REST 请求以持久化实体时,出现下一个错误:
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value
我的数据模型有以下实体:
合同:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING)
public class Contract implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY,
mappedBy="contract"
)
private List<Participation> participants = new ArrayList<Participation>();
private String name;
}
参与:
@Entity
public class Participation implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable = false) //By default the column will be CONTRACT_ID
private Contract contract;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
private Contact contact;
private String clauses;
}
联系方式:
@Entity
public class Contact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String emailAddress;
}
我有 2 个 JPARepositories:
public interface ContractRepository extends JpaRepository<Contract, Long> {
List<Contract> findByNameContainsIgnoreCase(String name);
}
public interface ContactRepository extends JpaRepository<Contact, Long> {
}
为了保存有几个参与的新合同,我正在 Postman 中执行以下步骤:
- 创建合同并获取其href:
请求:POST http://localhost:8080/api/contracts
主体:
{
"name": "Contract1"
}
响应成功:
201 Created
{
"name": "Contract1",
"participants": [],
"_links": {
"self": {
"href": "http://localhost:8080/api/contracts/4"
},
"contract": {
"href": "http://localhost:8080/api/contracts/4"
},
}
}
- 到目前为止一切顺利。现在我的合同仍然存在,我正在添加参与者: 联系人 1 已存在于数据库中。
请求:PATCH http://localhost:8080/api/contracts/4
主体:
{
"participants": [
{
"clauses": "Bla bla bla",
"contact": {
"href": "http://localhost:8080/api/contacts/1"
},
"contract": {
"href": "http://localhost:8080/api/contracts/4"
}
}
]
}
执行此请求时,系统会抱怨 field/fk 合约:
{
"cause": {
"cause": null,
"message": "not-null property references a null or transient value : com.xxx.xxx.model.Participation.contract"
},
"message": "not-null property references a null or transient value : com.xxx.xxx.model.Participation.contract; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.xxx.xxx.model.Participation.contract"
}
我尝试了几种方法在参与中引用合同,例如:
"contract": "http://localhost:8080/api/contracts/4"
运气不好。由于某种原因,系统将字段留空,而不是使用在步骤 1 中创建的实体的外键。 我做错了什么?
【问题讨论】:
-
使用 DTO 而不是实体与 json 一起发送
-
我可能会这样做,因为在公开的 API 和持久层之间有一层 DTO 是一个很好的做法。好吧,至少对于具有合理复杂程度的项目而言。不过,如果我保持这种方法并使用基于创建的 JPA 存储库的框架(Spring Data REST)自动公开的 API,我想知道如何做到这一点。它肯定有办法管理这个用例。
标签: spring spring-data-jpa spring-data-rest