CascadeType.ALL 和 "insertable = false, updatable = false" 互相排斥吗?

Do CascadeType.ALL and "insertable = false, updatable = false" exclude each other?

如果我有这样的配置,可以吗?

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "FOREIGN_ID", nullable = false, insertable = false, updatable = false)
ForeignClass foreignClass;

我认为不是,因为级联类型的行为与可插入和可更新参数冲突。

你怎么看?

长话短说,不,这些设置并不相互排斥。

想象一下,我们有以下模型。

create table APP_USER
(
   USER_ID number,
   USER_NAME varchar2(400),
   
   constraint APP_USER_PK primary key(USER_ID)
);

create table APP_BILLING_NUMBER
(
   BILL_ID number,
   BILL_ACCOUNT varchar2(20),
   BILL_BANK_NAME varchar2(300),
   BILL_USER_ID number,
   
   constraint APP_BILLING_NUMBER_PK primary key(BILL_ID),
);

以及适当的休眠映射:

@Entity
@Table(name = "APP_USER")
public class User
{
   @Id
   @Column(name = "USER_ID")
   private Long id;
   
   @Column(name = "USER_NAME")
   private String name;
}

@Entity
@Table(name = "APP_BILLING_NUMBER")
public class BillingNumber
{
   @Id
   @Column(name = "BILL_ID")
   private Long id;
   
   @Column(name = "BILL_ACCOUNT")
   private String account;
   
   @Column(name = "BILL_BANK_NAME")
   private String bankName;
   
   @ManyToOne
   @JoinColumn(name="BILL_USER_ID")
   private User user;
}

如果我们尝试做这样的事情:

  User user = new User();
  user.setId(1L);
  user.setName("Alex");
      
  BillingNumber bill = new BillingNumber();
  bill.setId(1L);
  bill.setAccount("EA12345678");
  bill.setBankName("BNP Paribas");
  bill.setUser(user);
      
  session.persist(bill);

我们会发现账单被添加到 APP_BILLING_NUMBER table,

SQL> select * from APP_BILLING_NUMBER;
BILL_ID BILL_ACCOUNT BILL_BANK_NAME BILL_USER_ID
------- ------------ -------------- ------------
1       EA12345678   BNP Paribas    1

但用户不是。发生这种情况是因为默认情况下我们有 @ManyToOne(cascade={})。如果我们想用 BillingNumber 实体持久化 User 实体,我们应该添加 CascadeType.PERSIST:

  @ManyToOne(cascade = {CascadeType.PERSIST})
  @JoinColumn(name="BILL_USER_ID")
  private User user;

那么,如果我们要使用 session.merge(bill) 操作,我们也应该添加 CascadeType.MERGE

现在想象一下,我们有

  @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
  @JoinColumn(name="BILL_USER_ID", insertable = false, updatable = false)
  private User user;

执行完上面的持久化操作后我们会得到:

SQL> select * from APP_USER;
USER_ID USER_NAME
------- ---------
1       Alex

SQL> select * from APP_BILLING_NUMBER;
BILL_ID BILL_ACCOUNT BILL_BANK_NAME BILL_USER_ID
------- ------------ -------------- ------------
1       EA12345678   BNP Paribas    (null)

如您所见,两个实体都已插入,但 APP_BILLING_NUMBER.BILL_USER_ID 引用是 null,因为 @JoinColumn(..., insertable = false, ...)。而且你不能更新它因为 updatable = false.

所以,这是有效但非常奇特的案例。

意思不同,互不冲突。

所以给定以下映射:

@Entity
@Table(name="player")
public class Player {


   @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
   @JoinColumn(name = "team_id", nullable = false, insertable = false, updatable = false)
   Team team;

}
  • cascade 表示在 player 上使用 EntityManagerpersist()merge() 时,JPA 将 自动呼叫persist()/merge()此玩家的队伍。

  • insertableupdatable 是关于是否允许分配新团队或更新玩家的团队。就数据库 table 而言,它是关于是否允许插入或更新 Player table 的 team_id 列的值。

所以一个是关于 inserting/updating Team table 中的记录,而另一个是关于 inserting/updating Player table 的值的 team_id 专栏,它们完全不同。