我定义了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/