Hibernate 将新元素保存在列表中而不删除旧元素
Posted
技术标签:
【中文标题】Hibernate 将新元素保存在列表中而不删除旧元素【英文标题】:Hibernate saves new Elements in List without deleting old ones 【发布时间】:2012-11-16 11:36:00 【问题描述】:我有两个对象; Document
和 DocumentBatch
文档
public class Document implements Serializable
....
private String documentId;
private DocumentBatch documentBatch;
....
DocumentBatch
public class DocumentBatch implements Serializable
private String batchId;
private List<Document> lDocuments = new LinkedList<Document>();
....
休眠映射:
<class name="Document" table="DOCUMENTS">
.....
<id name="documentID" column="DOCUMENT_ID" type="string" />
<many-to-one name="documentBatch" class="DocumentBatch" not-null="false"
cascade="save-update" lazy="false" insert="false" update="false">
<column name="BATCH_ID" not-null="true" />
</many-to-one>
......
</class>
<class name="DocumentBatch" table="DOCUMENT_BATCHES">
<id name="batchId" column="BATCH_ID" type="string" />
<list name="lDocuments" table="DOCUMENTS" cascade="all"
inverse="false" lazy="false" mutable="true">
<key not-null="true">
<column name="BATCH_ID" />
</key>
<list-index column="LIST_INDEX" base="0" />
<one-to-many class="Document" />
</list>
......
</class>
DocumentBatch
有一个Document
的列表,每次我运行我的测试用例并使用session.saveOrUpdate(documentBatch)
更新DocumentBatch
具有相同主键的对象,但使用新生成的文档对象列表(所有对象都是新生成的。 )。
Hibernate 将更新DocumentBatch
,保存带有索引的全新文档列表,但不删除列表中的旧元素。
所以当我运行我的测试用例两次并且每次 Document 列表有 5 个 Obj 时,我将有最后 10 个 objs。两个 index=0,两个 index=1,等等
所以它不会更新列表,而只会保存新列表。旧列表的元素可以在数据库中找到。当我尝试获取 DocumentBatch, DocumentBatch
时,有一个旧对象列表。
我该如何解决这个问题?哪里出错了?非常感谢。
更新 1:UnitTestCase
@Test
public void testSaveDocumentBatch() throws Throwable
....
String batchId = "500700";
DocumentBatch documentBatch = new DocumentBatch(batchId, name);
....
for (int i = 0; i < 5; i++)
String documentID = SessionIdentfierGenerator.nextSessionId();//generatting Id
Document document = new Document(documentID);
documentBatch.insertDocument(document);
....
session.saveOrUpdate(documentBatch);
....
和方法在类DocumentBatch中插入文档(文档文档):
public class DocumentBath
.....
private List<Document> lDocuments = new LinkedList<Document>();
.....
public void insertDocument(Document document)
lDocuments.add(document); // lDocuments is a list DocumentBatch
document.setDocumentBatch(this);
.....
更新 2:Oracle 数据库脚本:
文档
CREATE TABLE DOCUMENTS(
DOCUMENT_ID VARCHAR2(255 CHAR) NOT NULL,
BATCH_ID VARCHAR2(255 CHAR) NOT NULL,
...);
CREATE UNIQUE INDEX PK_DOCUMENT ON DOCUMENTS (DOCUMENT_ID);
ALTER TABLE DOCUMENTS ADD (CONSTRAINT PK_DOCUMENT PRIMARY KEY (DOCUMENT_ID) USING INDEX PK_DOCUMENT);
ALTER TABLE DOCUMENTS ADD (CONSTRAINT FK_DOCUMENT_BATCH_ID FOREIGN KEY (BATCH_ID) REFERENCES DOCUMENT_BATCHES (BATCH_ID) ON DELETE CASCADE);
DocumentBatch
CREATE TABLE DOCUMENT_BATCHES(
BATCH_ID VARCHAR2(255 CHAR) NOT NULL
...);
ALTER TABLE DOCUMENT_BATCHES ADD (
PRIMARY KEY (BATCH_ID));
【问题讨论】:
您能否在调用 saveOrUpdate 之前提供获取或创建 documentBatch 的代码。需要检查 documentBatch 对象是否是从数据库中获取的,还是每次都使用相同的 id 新创建的对象?? 感谢您的快速回复。我刚刚更新了原始帖子。 来自类 DocumentBatch 中的 List obj -- private List给你。在您的测试用例中,您正在为数据库中已经存在的实体创建新的实体对象。这会混淆 hibernate 并且 hibernate 不适合删除现有文档。
String batchId = "500700";
DocumentBatch documentBatch = new DocumentBatch(batchId, name);
首先使用 get() 或 load() 来获取 ID 500700 的现有 DocumentBatch 对象,而不是这个“new DocumentBatch(batchId, name)”。获取现有对象后,请执行以下步骤。
1) 创建一个方法,例如清除现有文档()。在此方法中,首先遍历文档列表并使 BATCH_ID 为空。一旦迭代完成,然后从列表中删除所有这些文档。
2) 现在在同一个空列表中添加新创建的文档。避免创建新的列表实例。使用相同的空列表实例并添加新文档。
这应该可以解决问题。由于这些步骤,hibernate 将知道最初存在一些现有值,现在这些值已被显式删除,因此 hibernate 将触发相关的删除查询。如果需要,也可以使用 orphan-delete。这将删除孤立的 DOcument 对象,而不是将它们保留在文档表中。
【讨论】:
你的答案很自然。你知道我可以说服 Hibernate 相信新创建的 ID 为 500700 的 DocumentBatch 是 DB 中的 DocumentBatch,但没有它的文档列表。所以如果有人只是创建了一个新的 DocumentBatch 而没有询问它是否已经存在,那么它将是不安全的。以上是关于Hibernate 将新元素保存在列表中而不删除旧元素的主要内容,如果未能解决你的问题,请参考以下文章