我定义了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可以包含在许多Command中,但不包含这些命令。

我有2个问题:


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



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



当级联类型为MERGE并且我在StockDetils中更改了一些详细信息,并使用更改后的StockDetails插入了新Command时,这不会更新现有记录
我尝试的示例:

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);



请帮助我解决:)

最佳答案

问题1


  当我尝试使用现有的StockDetails插入新命令时,出现“无法在对象中插入重复键...”的异常


我猜如果发生以下情况之一,就会发生这种情况:


您已经分离了StockDetails的实例,或者
手动设置StockDetails的ID,然后执行以下操作:

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

您有两种选择来解决此问题:


首先保存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


要么
cascade属性更改为CascadeType.PERSIST,在这种情况下,这是更好的选择(请参见上面的Solution1)。

关于java - jpa一对多插入重复键插入,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44550589/

10-13 00:07