【问题标题】:Spring not saving many-to-many mapping in DBSpring没有在数据库中保存多对多映射
【发布时间】:2022-02-04 21:01:21
【问题描述】:

我有 2 个实体。约会和项目。它们都是独立的,我们可以在多个约会中拥有多个项目。

约会类:

@Entity(name = "Appointment")
@Table(name = "appointment")
public class Appointment
{
    @Id
    @JsonProperty("appointment_id")
    @Column(name = "appointment_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonProperty("date")
    private Date startingTimestamp;

    @ManyToMany(mappedBy = "appointment",
        cascade = CascadeType.ALL)
    private List<Item> collectionOfItems;

    @JsonProperty("duration")
    private int duration;

    @JsonProperty("state")
    private AppoitmentState state;

    @ManyToOne
    @JsonBackReference
    @JoinColumn(name="user_appointment_owner_id", nullable = false)
    @JsonProperty("user_owner")
    private User user;

还有 Item 类:

@Entity
@Table(name = "item")
public class Item
{
    @Id
    @Column(name = "item_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long Id;

    @JsonProperty("name")
    private String name;

    @JsonProperty("duration")
    private int duration;

    @ManyToMany(targetEntity = Appointment.class,
        cascade = CascadeType.ALL)
    @JoinTable(name = "appointment_item", joinColumns = { @JoinColumn(name = "item_id") },
        inverseJoinColumns = { @JoinColumn(name = "appointment_id") })
    private List<Appointment> appointment;

    @ManyToMany
    @JsonProperty("set_of_professionals")
    @JsonIgnore
    private Set<Professional> professional;

    @JsonProperty("business_owning")
    private Long business_id;

这里省略了构造函数、getter 和 setter。

Appointment 控制器内部还有一个 patch 方法。

@RequestMapping(value = "appointment/{itemID}", method = RequestMethod.PATCH,  consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<Appointment> addItem(@PathVariable Long itemID, @RequestBody ObjectNode appointment_id_str)
{
    Long appointment_id = appointment_id_str.get("appoitment_id").asLong();
    Optional<Appointment> targetAppoitment = appointmentService.findById(appointment_id);
    Optional<Item> addedItem = itemService.findById(itemID);
    if (targetAppoitment.isPresent() && addedItem.isPresent())
    {
        Appointment appoitmentInDB = targetAppoitment.get();
        appoitmentInDB.addItem(addedItem.get());
        Appointment savedAppointment = appointmentService.save(appoitmentInDB);
        return new ResponseEntity<>(savedAppointment, HttpStatus.CREATED);
    }
    return new ResponseEntity("", HttpStatus.INTERNAL_SERVER_ERROR);
}

现在虽然在调试器中看到,一个项目已添加到 appoitment 的列表中,但保存不会 将更改刷新到数据库中。

这是数据库:

知道我错过了什么吗?

【问题讨论】:

    标签: java spring spring-data crud crud-repository


    【解决方案1】:

    是因为Item类自己的关系。

    如果您已经在 Appointment 类中描述了关系并在 Item 类中使用了 mappedBy,则不会出现此问题。这是因为 Hibernate 使用定义关系的类来维护它的关联。

    要解决此问题,您应该通过以下方式调整实体:

    class Appointment {
    
    ...
        
    @ManyToMany(targetEntity = Item.class,
            cascade = CascadeType.ALL)
        @JoinTable(name = "appointment_item", joinColumns = { @JoinColumn(name = "appointment_id") },
            inverseJoinColumns = { @JoinColumn(name = "item_id") })
        List<Item> collectionOfItems;
    
    ...
    
    }
    

    class Item {
    
    ...
    
        @ManyToMany(mappedBy = "collectionOfItems",
            cascade = CascadeType.ALL)
        private List<Appointment> appoitment;
    
    ...
    
    }
    

    这个问题已经在stackoverflow上回答了,link

    【讨论】:

    • 当你 @Autowire 类 A 和 B 相互之间时,通常会发生循环引用。所以检查你是否有类似class A { @Autowire private B b; }class B { @Autowire private A a; }
    • 你能再具体一点吗?您是否收到任何特定异常或您的应用程序无法启动?我不认为我明白你的意思。
    • 你的意思是当你向/appointment/{itemID} 发出请求时,你会得到这个无限循环。因为约会有一个项目,项目有一个约会:D
    • 据我从您的代码中看到,您返回的是 ResponseEntity&lt;Appointment&gt; 并且 Appointment 类是一个实体。由于您的 Appointment 包含一个 List&lt;Item&gt; 并且其中的每个 Item 都包含一个 Appointment 这就是您获得循环引用的原因。当 Spring 将您的约会类序列化为 JSON 对象时,它使用 getter 来执行此操作。您的 Appointment 包含一个方法 getCollectionOfItems() 并且在此集合中每个项目都有一个方法 getAppointment()
    • 要解决这个问题,我建议您创建一个新的 POJO,例如 AppointmentDTOItemDTO,并且只有 AppointmentDTO 包含 ItemDTO。完成数据库操作后,您会将返回的 Appointment 映射到 AppointmentDTO 并将 ResponseEntity&lt;AppointmentDTO&gt; 返回到端点的调用者。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 2020-11-28
    相关资源
    最近更新 更多