jpa一对多插入重复键插入

时间:2017-06-14 16:54:48

标签: java hibernate jpa

我定义了2个具有单向一对多关系的实体:

Command.class中的

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="STOCK_ID", referencedColumnName="id")
public StockDetails getStockDetails() {
    return stockDetails;
}
StockDetails.class中的

@Id
public String getId() {
    return id;
}

表示Command拥有一个StockDetails,StockDetails可以在许多命令中,但不能保存命令。

我有两个问题:

  1. 当我尝试使用现有的StockDetails插入新命令时,我得到了“无法在对象中插入重复键...”的异常 然后我将CascadeType更改为MERGE然后我没有得到此异常。 但是,当级联类型是MERGE时,当我有新的StockDetails但在DB中尚未存在时,我会得到例外
  2.   

    对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例

    1. 当级联类型为MERGE并且我更改了一些详细信息iN StockDetils,并使用更改的StockDetails插入新命令时,这不会更新现有记录 我尝试的例子:

      StockDetails sd1 = new StockDetails("GOOL", "Google Inc");
      Command c1 = new Command(123456l, 12345614l, sd1, GlobalVeriables.COMMAND_TYPE_ASK, 200, 300d, 1200d,
              new Date(System.currentTimeMillis()), GlobalVeriables.COMMAND_STATUS_OPEN); 
      commandManager.addNewCommand(c1);
      
      StockDetails sd2 = new StockDetails("GOOL", "Google Inc LTD");
      Command c2 = new Command(5674l, 5678l, sd2, GlobalVeriables.COMMAND_TYPE_ASK, 200, 300d, 1200d,
              new Date(System.currentTimeMillis()), GlobalVeriables.COMMAND_STATUS_OPEN); 
      commandManager.addNewCommand(c2);
      
    2. 请帮我解决:)

1 个答案:

答案 0 :(得分:1)

问题1

  

当我尝试在现有的StockDetails中插入新命令时,我得到了“无法在对象中插入重复键...”的

我想如果发生以下情况就会发生这种情况:

  1. 您已分离StockDetails
  2. 的实例
  3. 手动设置StockDetails的ID,然后执行以下操作:

    c1.setStockDetails(sd1);
    entityManager.persist(c1);
    

    这里发生的事情如下: 实体经理试图坚持c1。当CascadeType.PERSIST到位时,它会尝试在sd1上传播持久化操作,以发现数据库中存在一个具有相同ID的条目,导致约束违例异常。

    < / LI>

    解决方法1

    // start transaction here
    StockDetails sd1 = entityManager.find(StockDetails.class, <id_of_existing_stockdetails>);
    c1.setStockDetails(sd1);
    entityManager.persist(c1);
    // commit transaction here
    

    问题2

      

    对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例

    如果您执行以下操作,则会收到此异常:

    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name="STOCK_ID", referencedColumnName="id")
    public StockDetails getStockDetails() {
        return stockDetails;
    }
    

    StockDetails sd1 = new StockDetails("GOOL", "Google Inc");
    Command c1 = new Command(123456l, 12345614l, sd1,...);
    c1.setStockDetails(sd1);
    commandManager.addNewCommand(c1); // assuming this line is saving c1
    

    在这种情况下,您告诉实体经理要求c1为其分配一个新的sd1(未保存的实例)。现在实体管理器有一个问题:你告诉它在其外键字段中保存StockDetails的id,但是你关联的对象尚未保存且没有id(因为你告诉它传播)合并但不是PERSIST)。这就是你获得例外的原因。

    解决方案2

    您有两种方法可以解决问题:

    1. 首先保存sd1并将持久版本分配给c1并保存如下:

      // start transaction
      entityManager.persist(sd1);
      StockDetails sdPersistent = entityManager.find(StockDetails.class, <id>); // where id is the primary key of the newly saved sd1
      c1.setStockDetails(sdPersistent);
      entityManager.persist(c1);
      // commit transaction
      

    2. cascade属性更改为CascadeType.PERSIST,在这种情况下,这是更好的选择(参见上面的解决方案1)。