Hibernate 简单地从 JSON 添加元素到 manytomany
Hibernate simply adding elements to manytomany from JSON
我想通过请求在我的 manytomany 关联中添加元素,而不加载每个添加的元素。我正在使用自定义连接 table。 [代码将在底部添加]
例如这是 JSON 我得到:
{
"id": 122,
"materials": [
{
"id": {
"materialId": 62,
"homeworkId": 122
},
"position": 1
}
]
}
所以有一份家庭作业材料。如果我将其作为 POST 发送到服务器,则不会发生任何事情(如预期的那样)。对于以下所有示例,我仅使用 homeworkRepository.save(homework)
下面的方法也行得通。 (所有作业材料将按预期删除)
{
"id": 122,
"materials": []
}
但是如果我想像这样向材质中添加元素:
{
"id": 122,
"materials": [
{
"id": {
"materialId": 62,
"homeworkId": 122
},
"position": 1
},
{
"id": {
"materialId": 162,
"homeworkId": 122
},
"position": 1
}
]
}
会报错
attempted to assign id from null one-to-one property [schooling.api.courses.homework.ids.HomeworkMaterial.homework]
所以问题是,材料不是从数据库加载的,我只有 HomeworkMaterial 的 ID。所以我很确定,如果我只是循环遍历 HomeworkMaterials 并从数据库加载所有材料,它就可以工作。但在我看来,这确实不是一个好的解决方案,因为我认为我不需要访问数据库来添加那些 HomeworkMaterials,因为我在客户端上做了这个并且拥有材料的 ID,如果出现问题,只会抛出异常。
所以我的问题是,如何在不获取材料的情况下轻松保存更多的 HomeworkMaterials?
我也试过遍历它们并将它们保存在它们自己的存储库中,但这也不起作用。 (得到与以前的方法相同的异常)
所以现在我的代码:
Homework.java
@Getter @Setter @NoArgsConstructor
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Entity
@Table(name = "homework")
public class Homework {
private static final String sequenceName = "homework_id_sequence";
@Id
@Column(nullable = false)
@SequenceGenerator(allocationSize=10, sequenceName=sequenceName, name=sequenceName)
@GeneratedValue(generator=sequenceName, strategy= GenerationType.SEQUENCE)
protected Long id;
@OneToMany(mappedBy = "homework", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SUBSELECT)
@JsonIgnoreProperties(value = {"homework", "material"})
List<HomeworkMaterial> materials = new ArrayList<>();
public void addMaterial(Material material, int position) {
HomeworkMaterial homeworkMaterial = new HomeworkMaterial(material, this, position);
materials.add(homeworkMaterial);
material.getHomeworks().add(homeworkMaterial);
}
public void removeMaterial(Material material) {
for (int i = 0; i < materials.size(); i++) {
HomeworkMaterial current = materials.get(i);
if(current.getHomework().equals(this) && current.getMaterial().equals(material)) {
current.getHomework().getMaterials().remove(current);
current.setHomework(null);
current.setMaterial(null);
materials.remove(current);
}
}
}
// Equals and Hash omitted
}
Material.java
@Getter @Setter @NoArgsConstructor
@JsonIdentityInfo(scope = schooling.api.courses.materials.Material.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Entity
@Table(name="material")
public class Material implements FileOwner {
private static final String sequenceName = "material_id_sequence";
@Id
@Column(nullable = false)
@SequenceGenerator(allocationSize=10, sequenceName=sequenceName, name=sequenceName)
@GeneratedValue(generator=sequenceName, strategy=GenerationType.SEQUENCE)
protected Long id;
@OneToMany(mappedBy = "material", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SUBSELECT)
@JsonIgnoreProperties(value = {"homework", "material"})
List<HomeworkMaterial> homeworks = new ArrayList<>();
public void addHomework(Homework homework, int position) {
HomeworkMaterial homeworkMaterial = new HomeworkMaterial(this, homework, position);
homeworks.add(homeworkMaterial);
homework.getMaterials().add(homeworkMaterial);
}
public void removeHomework(Homework homework) {
for (int i = 0; i < homeworks.size(); i++) {
HomeworkMaterial current = homeworks.get(i);
if(current.getHomework().equals(homework) && current.getMaterial().equals(this)) {
current.getHomework().getMaterials().remove(current);
current.setHomework(null);
current.setMaterial(null);
homeworks.remove(current);
}
}
}
}
作业Material.java
@Getter @Setter @NoArgsConstructor
@Entity
@Table(name = "homework_material")
public class HomeworkMaterial {
@EmbeddedId
private HomeworkMaterialId id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("materialId")
private Material material;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("homeworkId")
private Homework homework;
@Column(nullable = false)
private int position;
public HomeworkMaterial(Material material, Homework homework, int position) {
this.material = material;
this.homework = homework;
this.position = position;
this.id = new HomeworkMaterialId(material.getId(), homework.getId());
}
}
HomeworkMaterialId.java
@Embeddable
@NoArgsConstructor @AllArgsConstructor @Getter @Setter
public class HomeworkMaterialId implements Serializable {
@Column(name = "material_id")
private long materialId;
@Column(name = "homework_id")
private long homeworkId;
}
如上所述,为了节省我只是简单地使用 homeworkRepository.save(homework)
我找到了一个解决方案,我可以使用 getById“获取”家庭作业和 Material,这样数据库就不会被访问,但我有一个对它们的引用,然后我可以保存它。
我想通过请求在我的 manytomany 关联中添加元素,而不加载每个添加的元素。我正在使用自定义连接 table。 [代码将在底部添加]
例如这是 JSON 我得到:
{
"id": 122,
"materials": [
{
"id": {
"materialId": 62,
"homeworkId": 122
},
"position": 1
}
]
}
所以有一份家庭作业材料。如果我将其作为 POST 发送到服务器,则不会发生任何事情(如预期的那样)。对于以下所有示例,我仅使用 homeworkRepository.save(homework)
下面的方法也行得通。 (所有作业材料将按预期删除)
{
"id": 122,
"materials": []
}
但是如果我想像这样向材质中添加元素:
{
"id": 122,
"materials": [
{
"id": {
"materialId": 62,
"homeworkId": 122
},
"position": 1
},
{
"id": {
"materialId": 162,
"homeworkId": 122
},
"position": 1
}
]
}
会报错
attempted to assign id from null one-to-one property [schooling.api.courses.homework.ids.HomeworkMaterial.homework]
所以问题是,材料不是从数据库加载的,我只有 HomeworkMaterial 的 ID。所以我很确定,如果我只是循环遍历 HomeworkMaterials 并从数据库加载所有材料,它就可以工作。但在我看来,这确实不是一个好的解决方案,因为我认为我不需要访问数据库来添加那些 HomeworkMaterials,因为我在客户端上做了这个并且拥有材料的 ID,如果出现问题,只会抛出异常。
所以我的问题是,如何在不获取材料的情况下轻松保存更多的 HomeworkMaterials?
我也试过遍历它们并将它们保存在它们自己的存储库中,但这也不起作用。 (得到与以前的方法相同的异常)
所以现在我的代码:
Homework.java
@Getter @Setter @NoArgsConstructor
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Entity
@Table(name = "homework")
public class Homework {
private static final String sequenceName = "homework_id_sequence";
@Id
@Column(nullable = false)
@SequenceGenerator(allocationSize=10, sequenceName=sequenceName, name=sequenceName)
@GeneratedValue(generator=sequenceName, strategy= GenerationType.SEQUENCE)
protected Long id;
@OneToMany(mappedBy = "homework", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SUBSELECT)
@JsonIgnoreProperties(value = {"homework", "material"})
List<HomeworkMaterial> materials = new ArrayList<>();
public void addMaterial(Material material, int position) {
HomeworkMaterial homeworkMaterial = new HomeworkMaterial(material, this, position);
materials.add(homeworkMaterial);
material.getHomeworks().add(homeworkMaterial);
}
public void removeMaterial(Material material) {
for (int i = 0; i < materials.size(); i++) {
HomeworkMaterial current = materials.get(i);
if(current.getHomework().equals(this) && current.getMaterial().equals(material)) {
current.getHomework().getMaterials().remove(current);
current.setHomework(null);
current.setMaterial(null);
materials.remove(current);
}
}
}
// Equals and Hash omitted
}
Material.java
@Getter @Setter @NoArgsConstructor
@JsonIdentityInfo(scope = schooling.api.courses.materials.Material.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Entity
@Table(name="material")
public class Material implements FileOwner {
private static final String sequenceName = "material_id_sequence";
@Id
@Column(nullable = false)
@SequenceGenerator(allocationSize=10, sequenceName=sequenceName, name=sequenceName)
@GeneratedValue(generator=sequenceName, strategy=GenerationType.SEQUENCE)
protected Long id;
@OneToMany(mappedBy = "material", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SUBSELECT)
@JsonIgnoreProperties(value = {"homework", "material"})
List<HomeworkMaterial> homeworks = new ArrayList<>();
public void addHomework(Homework homework, int position) {
HomeworkMaterial homeworkMaterial = new HomeworkMaterial(this, homework, position);
homeworks.add(homeworkMaterial);
homework.getMaterials().add(homeworkMaterial);
}
public void removeHomework(Homework homework) {
for (int i = 0; i < homeworks.size(); i++) {
HomeworkMaterial current = homeworks.get(i);
if(current.getHomework().equals(homework) && current.getMaterial().equals(this)) {
current.getHomework().getMaterials().remove(current);
current.setHomework(null);
current.setMaterial(null);
homeworks.remove(current);
}
}
}
}
作业Material.java
@Getter @Setter @NoArgsConstructor
@Entity
@Table(name = "homework_material")
public class HomeworkMaterial {
@EmbeddedId
private HomeworkMaterialId id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("materialId")
private Material material;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("homeworkId")
private Homework homework;
@Column(nullable = false)
private int position;
public HomeworkMaterial(Material material, Homework homework, int position) {
this.material = material;
this.homework = homework;
this.position = position;
this.id = new HomeworkMaterialId(material.getId(), homework.getId());
}
}
HomeworkMaterialId.java
@Embeddable
@NoArgsConstructor @AllArgsConstructor @Getter @Setter
public class HomeworkMaterialId implements Serializable {
@Column(name = "material_id")
private long materialId;
@Column(name = "homework_id")
private long homeworkId;
}
如上所述,为了节省我只是简单地使用 homeworkRepository.save(homework)
我找到了一个解决方案,我可以使用 getById“获取”家庭作业和 Material,这样数据库就不会被访问,但我有一个对它们的引用,然后我可以保存它。