JPA @一对多和@多对一:尽管包含mappedBy,但反向引用为空

2w3kk1z5  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(221)

我有4个实体,彼此之间有@OneToMany关系。当我尝试保存包含OrderItemOrder时,Orderitem没有反向引用。
在下面的代码中,为了简洁起见,只显示了重要的字段(通常的字符串和原语被省略了)。我决定还包括DishUser实体。

订单:

@Entity
@NoArgsConstructor
@Getter
@Setter
@ToString
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;

    @OnDelete(action = OnDeleteAction.CASCADE)
    @OneToMany(
        mappedBy = "order",
        cascade = CascadeType.ALL,
        fetch = FetchType.EAGER,
        orphanRemoval = true)
    private List < OrderItem > orderItems;
}

菜品:

@Entity
@NoArgsConstructor
@Getter
@Setter
@ToString
public class Dish {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany(cascade = CascadeType.ALL,
        fetch = FetchType.LAZY,
        mappedBy = "dish")
    @ToString.Exclude
    private List < OrderItem > orderItems;
}

订单项目:

@Entity
@NoArgsConstructor
@Getter
@Setter
@ToString
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @ToString.Exclude
    private Dish dish;
    @ManyToOne(fetch = FetchType.LAZY)
    private Order order;
    private int quantity;
}

使用者:

@Entity
@NoArgsConstructor
@Getter
@Setter
@ToString
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

    @OneToMany(
        mappedBy = "user",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List < Order > orders;
}

当我试图用Spring Data JPA保存Order时,出现了这个问题。让我们在保存之前打印Order以查看OrderItem

public Order saveOrder(Order order) {
    System.out.println("SERVICE saving order " + order);
    return orderRepository.save(order);
}

正如您所看到的,orderItems backreference在保存之前为null(我认为spring data jpa应该处理它的设置)。
服务保存订单订单(标识=0,orderItems=[订单项(标识=0,数量=2,订单=空)])
下面是我在DB中的内容(Order和OrderItem实体)。

k5ifujac

k5ifujac1#

OrderItem类中,添加以下注解:

@ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST}, fetch=FetchType.LAZY)
@JoinColumn(name="order_id", referencedColumnName="id", nullable = false)
Order order.

还有一点,我建议你使用SEQUENCE_GENERATOR,因为IDENTITY意味着:我将创建一个空ID的实体,数据库将为我生成一个ID。我认为Postgres甚至不支持这一点,即使它支持,序列生成器也是一个更好、更有效的选择。

nkcskrwz

nkcskrwz2#

最好的选择,我发现这是这样做:

order.getOrderItems().forEach(orderItem -> orderItem.setOrder(order));

save()调用之前。即使此时order没有被持久化,Hibernate似乎可以解析关系,并且将正确设置向后引用。
如果您不想在业务逻辑中设置反向引用,则可以向实体中添加如下内容:

class Order {
    ...
    @PrePersist
    public void prePersist() {
        setMissingBackReferences();
    }

    private void setMissingBackReferences() {
        orderItems.forEach(oderItem -> {
            if (oderItem.getOrder() == null) {
                oderItem.setOrder(this);
            }
        });
    }
    ...
}

相关问题