Spring 数据剩余 - 无法更新 (PATCH) child 个引用了另一个实体的实体列表
Spring Data Rest - can not update (PATCH) a list of child entities that have a reference to another entity
我有三个实体:Parent、它的 Child 和一些参考资料:
Parent
@Entity
@Table(name = "parents")
public class Parent extends LongId {
@NonNull
@Column(nullable = false)
private String name = "Undefine";
@NonNull
@OneToMany(cascade = MERGE)
private List<Child> children = new ArrayList<>();
}
Child
@Entity
@Table(name = "children")
public class Child extends LongId {
@NonNull
@Column(nullable = false)
private String name;
@NonNull
@ManyToOne(optional = false)
private Reference reference;
}
参考
@Entity
@Table(name = "references")
public class Reference extends LongId {
@NotEmpty
@Column(nullable = false)
@Length(min = 3)
@NonNull
private String description;
}
及其存储库:
@RepositoryRestResource
public interface ParentRepo extends JpaRepository<Parent, Long> {
}
@RepositoryRestResource
public interface ChildRepo extends JpaRepository<Child, Long> {
}
@RepositoryRestResource
public interface ReferenceRepo extends JpaRepository<Reference, Long> {
}
之前我坚持了几个 Children 与参考文献。然后我用一个 child:
创建了一个新的 Parent
POST http://localhost:8080/api/parents
{
"name" : "parent2",
"children" : [
"http://localhost:8080/api/children/3"
]
}
并且已成功获得状态 201 Created。
但是当我尝试将另一个 child 添加到 parent2 (用 PATCH 更新它)时:
PATCH http://localhost:8080/api/parents/2
{
"name" : "parent2",
"children" : [
"http://localhost:8080/api/children/3",
"http://localhost:8080/api/children/4"
]
}
我有一个错误:
{
"cause": {
"cause": null,
"message": "Can not construct instance of restsdemo.domain.entity.Child: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/children/4')\n at [Source: N/A; line: -1, column: -1]"
},
"message": "Could not read payload!; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of restsdemo.domain.entity.Child: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/children/4')\n at [Source: N/A; line: -1, column: -1]"
}
如果我从 Child 中删除 link 到引用实体:
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "children")
public class Child extends LongId {
@NonNull
@Column(nullable = false)
private String name;
// @NonNull
// @ManyToOne(optional = false)
// private Reference reference;
}
一切正常 - child4 已成功添加到 parent2.
如果 child 个实体引用了另一个实体,你能告诉我如何正确更新它们吗?
这里有这个例子的回购:https://github.com/Cepr0/restdemo
我简直不敢相信!!!
我向 Child 添加了一个带有 String 参数的空构造函数,一切正常!
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "children")
public class Child extends LongId {
@NonNull
@Column(nullable = false)
private String name;
@NonNull
@ManyToOne(optional = false)
private Reference reference;
public Child(String reference) {
}
}
谁能解释一下它为什么有效?!
None 这些解决方案都有效。当然,您可以创建一个接受字符串的假虚拟构造函数,这样错误就会消失,但这似乎没什么用! (例如,它会在字符串 uri 中传递,例如 localhost:8080/address/1
,这是无用的,因为没有解决方案恰好将其映射到域实体。
根据我的研究,没有办法让它发挥作用。一旦实现了自定义控制器,就无法再自动将 URI 从 @RequestBody
对象转换为存储库管理的域实体。基本上 spring data rest 添加了秘诀来解析无法在您定义的手动控制器中访问的 URI。
您可能可以实施一些方法来创建 URI 解析器,但祝您好运,因为它很可能没有记录。
作为解决方法或 'hack'.. 尝试只使用 spring 数据 rest 存储库端点,甚至可能像 @HandleBeforeSave
这样的存储库事件挂钩,或者如果这不是我的选择考虑过这个。
这行不通,因为 URI 不会映射到实体
{
"name": "joe",
"addresses": ["localhost:8080/address/1",
"localhost:8080/address/8",
"localhost:8080/address/23"]
}
而是创建一个 DTO 并传入主键,您可以在自定义控制器中执行自己的解析(例如,通过 AddressRepository 中的主键获取地址)。这是一种相当手动的方法,显然并不理想。
{
"name": "joe",
"addresses": [1, 8, 23]
}
我有三个实体:Parent、它的 Child 和一些参考资料:
Parent
@Entity
@Table(name = "parents")
public class Parent extends LongId {
@NonNull
@Column(nullable = false)
private String name = "Undefine";
@NonNull
@OneToMany(cascade = MERGE)
private List<Child> children = new ArrayList<>();
}
Child
@Entity
@Table(name = "children")
public class Child extends LongId {
@NonNull
@Column(nullable = false)
private String name;
@NonNull
@ManyToOne(optional = false)
private Reference reference;
}
参考
@Entity
@Table(name = "references")
public class Reference extends LongId {
@NotEmpty
@Column(nullable = false)
@Length(min = 3)
@NonNull
private String description;
}
及其存储库:
@RepositoryRestResource
public interface ParentRepo extends JpaRepository<Parent, Long> {
}
@RepositoryRestResource
public interface ChildRepo extends JpaRepository<Child, Long> {
}
@RepositoryRestResource
public interface ReferenceRepo extends JpaRepository<Reference, Long> {
}
之前我坚持了几个 Children 与参考文献。然后我用一个 child:
创建了一个新的 ParentPOST http://localhost:8080/api/parents
{
"name" : "parent2",
"children" : [
"http://localhost:8080/api/children/3"
]
}
并且已成功获得状态 201 Created。 但是当我尝试将另一个 child 添加到 parent2 (用 PATCH 更新它)时:
PATCH http://localhost:8080/api/parents/2
{
"name" : "parent2",
"children" : [
"http://localhost:8080/api/children/3",
"http://localhost:8080/api/children/4"
]
}
我有一个错误:
{
"cause": {
"cause": null,
"message": "Can not construct instance of restsdemo.domain.entity.Child: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/children/4')\n at [Source: N/A; line: -1, column: -1]"
},
"message": "Could not read payload!; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of restsdemo.domain.entity.Child: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/children/4')\n at [Source: N/A; line: -1, column: -1]"
}
如果我从 Child 中删除 link 到引用实体:
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "children")
public class Child extends LongId {
@NonNull
@Column(nullable = false)
private String name;
// @NonNull
// @ManyToOne(optional = false)
// private Reference reference;
}
一切正常 - child4 已成功添加到 parent2.
如果 child 个实体引用了另一个实体,你能告诉我如何正确更新它们吗?
这里有这个例子的回购:https://github.com/Cepr0/restdemo
我简直不敢相信!!! 我向 Child 添加了一个带有 String 参数的空构造函数,一切正常!
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "children")
public class Child extends LongId {
@NonNull
@Column(nullable = false)
private String name;
@NonNull
@ManyToOne(optional = false)
private Reference reference;
public Child(String reference) {
}
}
谁能解释一下它为什么有效?!
None 这些解决方案都有效。当然,您可以创建一个接受字符串的假虚拟构造函数,这样错误就会消失,但这似乎没什么用! (例如,它会在字符串 uri 中传递,例如 localhost:8080/address/1
,这是无用的,因为没有解决方案恰好将其映射到域实体。
根据我的研究,没有办法让它发挥作用。一旦实现了自定义控制器,就无法再自动将 URI 从 @RequestBody
对象转换为存储库管理的域实体。基本上 spring data rest 添加了秘诀来解析无法在您定义的手动控制器中访问的 URI。
您可能可以实施一些方法来创建 URI 解析器,但祝您好运,因为它很可能没有记录。
作为解决方法或 'hack'.. 尝试只使用 spring 数据 rest 存储库端点,甚至可能像 @HandleBeforeSave
这样的存储库事件挂钩,或者如果这不是我的选择考虑过这个。
这行不通,因为 URI 不会映射到实体
{
"name": "joe",
"addresses": ["localhost:8080/address/1",
"localhost:8080/address/8",
"localhost:8080/address/23"]
}
而是创建一个 DTO 并传入主键,您可以在自定义控制器中执行自己的解析(例如,通过 AddressRepository 中的主键获取地址)。这是一种相当手动的方法,显然并不理想。
{
"name": "joe",
"addresses": [1, 8, 23]
}