【问题标题】:Do CascadeType.ALL and "insertable = false, updatable = false" exclude each other?CascadeType.ALL 和“insertable = false, updatable = false”是否相互排斥?
【发布时间】:2020-03-18 15:17:46
【问题描述】:

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

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

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

你怎么看?

【问题讨论】:

    标签: java hibernate spring-data-jpa spring-data hibernate-mapping


    【解决方案1】:

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

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

    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表中,

    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而无法更新。

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

    【讨论】:

      【解决方案2】:

      它们的含义不同,并且彼此不冲突。

      所以给出以下映射:

      @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 是关于是否允许分配新团队或更新团队的球员。就DB表而言,就是Player表的team_id列的值是否允许插入或更新。

      一个是关于在Team 表中插入/更新记录,而另一个是关于插入/更新Player 表的team_id 列的值,这是完全不同的事情。

      【讨论】:

        猜你喜欢
        • 2011-06-17
        • 2011-04-17
        • 2013-04-10
        • 2016-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多