我定义了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可以在许多命令中,但不能保存命令。
我有两个问题:
对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例
当级联类型为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);
请帮我解决:)
答案 0 :(得分:1)
当我尝试在现有的StockDetails中插入新命令时,我得到了“无法在对象中插入重复键...”的
我想如果发生以下情况就会发生这种情况:
StockDetails
或手动设置StockDetails
的ID,然后执行以下操作:
c1.setStockDetails(sd1);
entityManager.persist(c1);
这里发生的事情如下:
实体经理试图坚持c1
。当CascadeType.PERSIST
到位时,它会尝试在sd1
上传播持久化操作,以发现数据库中存在一个具有相同ID的条目,导致约束违例异常。
// start transaction here
StockDetails sd1 = entityManager.find(StockDetails.class, <id_of_existing_stockdetails>);
c1.setStockDetails(sd1);
entityManager.persist(c1);
// commit transaction here
对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例
如果您执行以下操作,则会收到此异常:
@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)。这就是你获得例外的原因。
您有两种方法可以解决问题:
首先保存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
,在这种情况下,这是更好的选择(参见上面的解决方案1)。