繁体   English   中英

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

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

我有以下域模型

users
----
id (PK)
name

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

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

在使用 JPA 更新用户时,如果我尝试使用清除关联的订单集合

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

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

更新

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

@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;
    }
}

你能告诉我映射会有什么变化吗?

更新:

也尝试了以下映射:

@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;
    }
}

在插入时,它抱怨说“为:class Order 生成了 null id”(也尝试过使用 insertable=true 和 updatable=true)

您可以使用标识符保持连接,并确保删除不会尝试使用集合上的可更新和可插入注释将 null 写入集合 FK。

@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;
}

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

part 表示子表不会更新,但可以删除

这里的原因是关联是单向的,所以User是拥有方(因为它是唯一的一方)。

使关联双向并使Order成为关联所有者。 这样您就可以避免冗余更新(而not null违反not null约束)。

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

用户类

@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();
    }
}

订单类

@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;
    }
}

要删除的代码

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

生成的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=?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM