2017-06-14 83 views
0

我定義2個實體單向一對多關係:JPA一對多插入重複鍵插入

在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可以在許多命令中,但不是h執行命令。

我有2個問題:

  1. 當我試圖插入與我得到異常現有StockDetails新的命令「不能在對象中插入重複鍵......」 後來我改變了CascadeType的合併然後我沒有得到這個例外。 但是,當級聯類型是MERGE,當我在DB有新StockDetails這不是exsits的是,我得到

對象異常引用了一個未保存的瞬態的實例 - 沖洗

之前保存的瞬態的實例
  • 當級聯型合併,我改變了一些細節在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); 
    
  • 請幫我SOLV說:)

    回答

    1

    問題1

    當我試圖插入與我得到異常現有StockDetails新的命令「不能插入重複鍵對象...「

    我想這會發生如果發生下列情況之一:

    1. 你已經脫離實例StockDetails,或
    2. 手動設置的StockDetails的ID,並做folloing:

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

      這裏發生的事情是這樣的: 實體管理器試圖堅持c1。由於CascadeType.PERSIST已到位,因此它會嘗試傳播sd1上的持久操作,以發現數據庫中存在具有導致違反約束異常的相同ID的條目。

    解決方法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(因爲您要傳播MERGE而不是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)。