Spring Data JPA - 删除子实体而不是在更新时设置为null?

时间:2021-11-08 06:04:52

I have the following domain model

我有以下域模型

users
----
id (PK)
name

orders
------
id (PK)
userid (PK)
name

Orders.userid references id in User and is part of the composite primary key. (I need userid in the primary key since it is a partition key and in MySQL we cannot create the primary key without the partition key)

Orders.userid在User中引用id,并且是复合主键的一部分。 (我需要主键中的userid,因为它是一个分区键,而在MySQL中我们不能创建没有分区键的主键)

On using JPA to update User, if I try to clear the associated orders collection using

如果我尝试使用JPA来清除相关的订单集合,则使用JPA更新用户

User user = userRepository.getOne(id);
user.getOrders().clear();
userRepository.save(user);

JPA first tries to set userid to null on the associated Orders and then delete the row. This fails since userid is non-nullable and part of the primary key. Is there a way to tell JPA that it simply needs to go an delete the Order rows without setting the userid column to null first?

JPA首先尝试在关联的Orders上将userid设置为null,然后删除该行。由于userid不可为空并且是主键的一部分,因此失败。有没有办法告诉JPA它只需要删除Order行而不先将userid列设置为null?

UPDATE

Mapping: The mapping I have is something like this:

映射:我的映射是这样的:

@Entity
@Table(name = "users")
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id")
    public Long id;

    @Column(name="name")
    private String name;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name="userid", referencedColumnName = "id", insertable = true, updatable = true)
    @Fetch(FetchMode.JOIN)
    private Set<Order> orders;

}

@Entity
@Table(name = "orders")
@IdClass(Order.OrderPk.class)
public class Order implements Serializable {

    @Id
    @Column(name="id")
    private Long id;

    @Id
    @Column(name="userid")
    private Long userId;

    @Column(name="name")
    private String name;

    public static class OrderPk implements Serializable  {

        private Long id;

        private Long userId;
    }
}

Can you tell me what would be the change to the mapping?

你能告诉我映射的变化是什么吗?

UPDATE:

Tried the following mapping too:

尝试了以下映射:

@Entity
@Table(name = "users")
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id", nullable = false)
    public Long id;

    @Column(name="name")
    private String name;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "orderPk.user")
    @Fetch(FetchMode.JOIN)
    private Set<Order> orders;
}

@Entity
@Table(name = "orders")
public class Order implements Serializable {

    @EmbeddedId
    private OrderPk orderPk;

    @Column(name="name")
    private String name;

    @Embeddable
    public static class OrderPk implements Serializable {

        @GeneratedValue
        @Column(name="id", insertable = false, updatable = false, nullable = false)
        private Long id;

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name="userid", referencedColumnName = "id", insertable = false, updatable = false, nullable = false)
        private User user;
    }
}

On insert, it complains saying "null id generated for:class Order" (Have also tried with insertable=true and updatable=true)

在插入时,它抱怨说“为类生成的null id:class order”(还尝试使用insertable = true和updatable = true)

2 个解决方案

#1


0  

The cause here is that the association is uni-directional, so User is the owning side (because it's the only side).

这里的原因是关联是单向的,因此用户是拥有者(因为它是唯一的一方)。

Make the association bidirectional and make Order the association owner. That way you will avoid redundant updates (and not null constraint violations).

使关联双向并使订单成为关联所有者。这样您就可以避免冗余更新(而不是违反空约束)。

#2


0  

The following entity mapping works for me. Removed all getters and setters for brevity.

以下实体映射适用于我。为简洁起见,删除了所有的getter和setter。

User Class

用户类

@Entity
public class User {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

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

    public void removeOrder(Orders orders) {
        orders.setUserId(null);
        this.orders.remove(orders);
    }

    public void removeAllOrders() {
        orders.forEach(order -> order.setUserId(null));
        this.orders.clear();
    }
}

Order Class

订单类

@Entity
@IdClass(Orders.OrderPk.class)
public class Orders {

    @Id
    private Integer id;

    @Id
    @ManyToOne
    @JoinColumn(name = "userid")
    private User userId;

    private String name;

    public static class OrderPk implements Serializable {
        private Integer id;
        private Integer userId;
    }
}

Code to Remove

要删除的代码

@Override
@Transactional
public void run(String... args) throws Exception {
    User user = userRepository.findOne(1);
    user.removeAllOrders();
    userRepository.save(user);
    System.out.println("Done");
}

Sql generated

生成了Sql

Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select orders0_.userid as userid2_1_0_, orders0_.id as id1_0_0_, orders0_.userid as userid2_0_0_, orders0_.id as id1_0_1_, orders0_.userid as userid2_0_1_, orders0_.name as name3_0_1_ from orders orders0_ where orders0_.userid=?
Done
Hibernate: delete from orders where id=? and userid=?
Hibernate: delete from orders where id=? and userid=?

#1


0  

The cause here is that the association is uni-directional, so User is the owning side (because it's the only side).

这里的原因是关联是单向的,因此用户是拥有者(因为它是唯一的一方)。

Make the association bidirectional and make Order the association owner. That way you will avoid redundant updates (and not null constraint violations).

使关联双向并使订单成为关联所有者。这样您就可以避免冗余更新(而不是违反空约束)。

#2


0  

The following entity mapping works for me. Removed all getters and setters for brevity.

以下实体映射适用于我。为简洁起见,删除了所有的getter和setter。

User Class

用户类

@Entity
public class User {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

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

    public void removeOrder(Orders orders) {
        orders.setUserId(null);
        this.orders.remove(orders);
    }

    public void removeAllOrders() {
        orders.forEach(order -> order.setUserId(null));
        this.orders.clear();
    }
}

Order Class

订单类

@Entity
@IdClass(Orders.OrderPk.class)
public class Orders {

    @Id
    private Integer id;

    @Id
    @ManyToOne
    @JoinColumn(name = "userid")
    private User userId;

    private String name;

    public static class OrderPk implements Serializable {
        private Integer id;
        private Integer userId;
    }
}

Code to Remove

要删除的代码

@Override
@Transactional
public void run(String... args) throws Exception {
    User user = userRepository.findOne(1);
    user.removeAllOrders();
    userRepository.save(user);
    System.out.println("Done");
}

Sql generated

生成了Sql

Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select orders0_.userid as userid2_1_0_, orders0_.id as id1_0_0_, orders0_.userid as userid2_0_0_, orders0_.id as id1_0_1_, orders0_.userid as userid2_0_1_, orders0_.name as name3_0_1_ from orders orders0_ where orders0_.userid=?
Done
Hibernate: delete from orders where id=? and userid=?
Hibernate: delete from orders where id=? and userid=?