Spring Data JPA - Delete child entities instead of setting to null on update?

删除回忆录丶 提交于 2019-12-24 12:43:27

问题


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)

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

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?

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)


回答1:


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:


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

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

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=?



回答3:


You can keep the join using the identifier, and ensure the delete doesn't attempt to write null to the collection FK using the updatable and insertable annotations on the collection.

@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)
    @JoinColumn(name = "userId", updatable = false, insertable = false)
    private Set<Order> orders;
}

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

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

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

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

The

@JoinColumn(name = "userId", updatable = false, insertable = false)

part means the child table won't be updated, but can be deleted



来源:https://stackoverflow.com/questions/35143661/spring-data-jpa-delete-child-entities-instead-of-setting-to-null-on-update

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!