【问题标题】:Can't save a OneToMany/ManyToOne relationship in Spring Data REST request无法在 Spring Data REST 请求中保存 OneToMany/ManyToOne 关系
【发布时间】: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 中执行以下步骤:

  1. 创建合同并获取其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. 到目前为止一切顺利。现在我的合同仍然存在,我正在添加参与者: 联系人 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


【解决方案1】:

问题可以通过以下方式解决:

  1. 添加新的存储库 ParticipationRepository(扩展 JpaRepository);
  2. 首先创建一个不参与的合同:

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"
    }
  }
}
  1. 创建一个参与并使用刚刚创建的合同中的 URI 来设置 FK。假设联系人 1 已存在于数据库中。

POST http://localhost:8080/api/participations { “条款”:“bla,bla,bla”, "合同": "http://localhost:8080/api/contracts/3", “联系人”:“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"
    }
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-18
    • 2016-09-26
    • 1970-01-01
    • 2023-04-09
    • 2016-04-17
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多