无法在 Spring 数据 REST 请求中保存 OneToMany/ManyToOne 关系
Can't save a OneToMany/ManyToOne relationship in Spring Data REST request
我正在使用 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 已存在于数据库中。
请求:补丁 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 中创建的实体的外键。
我做错了什么?
问题可以通过以下方式解决:
- 添加一个新的存储库 ParticipationRepository(扩展 JpaRepository);
- 首先创建一个没有参与的合约:
POST http://localhost:8080/api/contracts { "name": "Contract1" }
回复:
201 Created
{
"name": "Contract1",
"_links": {
"self": {
"href": "http://localhost:8080/api/contracts/3"
},
"contract": {
"href": "http://localhost:8080/api/contracts/3"
},
"participants": {
"href": "http://localhost:8080/api/contracts/3/participants"
}
}
}
- 创建一个参与并使用刚刚创建的合约中的 URI 来设置 FK。假设联系人 1 已经存在于数据库中。
POST http://localhost:8080/api/participations {
"clauses": "bla, bla, bla",
"contract": "http://localhost:8080/api/contracts/3",
"contact": "http://localhost:8080/api/contacts/1" }
回复:
201 Created
{
"clauses": "bla, bla, bla",
"_links": {
"self": {
"href": "http://localhost:8080/api/participations/5"
},
"participation": {
"href": "http://localhost:8080/api/participations/5"
},
"contract": {
"href": "http://localhost:8080/api/participations/5/contract"
},
"contact": {
"href": "http://localhost:8080/api/contacts/5/contact"
}
}
}
我正在使用 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 已存在于数据库中。
请求:补丁 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 中创建的实体的外键。 我做错了什么?
问题可以通过以下方式解决:
- 添加一个新的存储库 ParticipationRepository(扩展 JpaRepository);
- 首先创建一个没有参与的合约:
POST http://localhost:8080/api/contracts { "name": "Contract1" }
回复:
201 Created
{
"name": "Contract1",
"_links": {
"self": {
"href": "http://localhost:8080/api/contracts/3"
},
"contract": {
"href": "http://localhost:8080/api/contracts/3"
},
"participants": {
"href": "http://localhost:8080/api/contracts/3/participants"
}
}
}
- 创建一个参与并使用刚刚创建的合约中的 URI 来设置 FK。假设联系人 1 已经存在于数据库中。
POST http://localhost:8080/api/participations { "clauses": "bla, bla, bla", "contract": "http://localhost:8080/api/contracts/3", "contact": "http://localhost:8080/api/contacts/1" }
回复:
201 Created
{
"clauses": "bla, bla, bla",
"_links": {
"self": {
"href": "http://localhost:8080/api/participations/5"
},
"participation": {
"href": "http://localhost:8080/api/participations/5"
},
"contract": {
"href": "http://localhost:8080/api/participations/5/contract"
},
"contact": {
"href": "http://localhost:8080/api/contacts/5/contact"
}
}
}