我正在使用MySQL數據庫構建ADF Fusion Web應用程序(12c)。Oracle ADF - 在父實體創建時創建子實體
爲了在插入時獲得自動遞增的PK值,我使用了爲自動遞增PK字段分配「AutoIncrementProperty」屬性集(屬性「AI」,值「true」)的方法。所有實體都從覆蓋doDML()的類擴展而來。這一切都很好,但FYI,這是我使用的代碼:
protected void doDML(int i, TransactionEvent transactionEvent) {
super.doDML(i, transactionEvent);
if (i == DML_INSERT) {
populateAutoincrementAtt();
}
}
/*
* Determines if the Entity PK is marked as an autoincrement col
* and executes a MySQL function to retrieve the last insert id
*/
private void populateAutoincrementAtt() {
EntityDefImpl entdef = this.getEntityDef();
AttributeDef pk = null;
//look for primary key with Autoincrement property set
for (AttributeDef att : entdef.getAttributeDefs()) {
if (att.isPrimaryKey() && (att.getProperty("AI") != null)) {
pk = att;
break;
}
}
if (pk != null) {
try (PreparedStatement stmt =
this.getDBTransaction()
.createPreparedStatement("SELECT last_insert_id()", 1)) {
stmt.execute();
try (ResultSet rs = stmt.getResultSet()) {
if (rs.next()) {
setAttribute(pk.getName(), rs.getInt(1));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
好的,這不是問題。這是應該的。
我有兩個實體與相應的MySQL表。我們稱他們爲「人」和「文件夾」。文件夾實體/表是遞歸之多,因而它看起來像這樣:
文件夾
- ID(自動遞增的PK整數)
- parentId的(外鍵父文件夾對象)
- folderName
- ...
而且,Person實體/表看起來是這樣的:
人
- ID(自動遞增的PK整數)
- 的userName
- rootFolderId(Folder tabl的外鍵E)
- ...
所以,一個人有分配給他/她的根文件夾。 (該文件夾可能會有一個子文件夾層次結構)
我遇到的問題是,當我創建一個Person實體時,我想創建一個新的Folder實體,獲取它的PK值,然後指定整數到新的Person的rootFolderId屬性。
應該很簡單,不是嗎?
在PersonImpl的類(擴展EntityImpl),我有以下方法:
private Integer createRootFolder() {
Integer newIdAssigned;
String entityName = "com.my.model.entity.Folder";
EntityDefImpl folderDef = EntityDefImpl.findDefObject(entityName);
EntityImpl newFolder = (EntityImpl) folderDef.createInstance2(getDBTransaction(), null);
newFolder.setAttribute("folderName", "ROOT");
try {
getDBTransaction().commit();
newIdAssigned = (Integer) newCollection.getAttribute("Id");
} catch (JboException ex) {
getDBTransaction().rollback();
newIdAssigned = null;
}
return newIdAssigned;
}
所以,這種方法工作得很好。它確實插入一個Folder對象並返回它的PK值。問題出現在何時/何地/如何稱此方法。
我可以從PersonImpl的的創建方法調用,就像這樣:
protected void create(AttributeList attributeList) {
Integer rootFolderId = null;
rootFolderId = createRootFolder();
super.create(attributeList);
this.setRootFolderId(rootFolderID);
}
但是,當然,這會在根文件夾對象之前所屬Person對象被提交給數據庫。所以,如果Person永遠不會被提交,我們就會有一個我們無緣無故創建的孤立的Folder對象。
我在PersonImpl的類打過電話從doDML()這樣的:
protected void doDML(int operation, TransactionEvent e) {
Integer rootFolderId;
super.doDML(operation, e);
if (operation == DML_INSERT) {
rootFolderId = createRootFolder();
if (rootFolderId != null) {
this.setRootCollectionId(rootCollID);
getDBTransaction().commit();
}
}
}
但是......當然,當createRootFolder()調用commit(),這將導致doDML()火再次,我們得到一個遞歸問題。我玩過像設置標誌這樣的kludges來防止遞歸doDML()調用,但它們都有問題。而且,我認爲我一定會忽略一些簡單的東西。
這將是理想的,如果我可以在實體本身中以聲明方式執行此操作,而無需代碼。但是,我認爲編碼解決方案會非常簡單。我只是沒有看到它。
任何用語?
你爲什麼不研究viewObjects?在兩者之間創建一個viewLink。在你的案例中,人物大師1-1與person.folderid = folder.id中鏈接的子文件夾的關係。這樣,當您在人的視圖對象中創建一個新人時,您還可以創建一個文件夾行,該行將自動從主服務器獲取FK ID的值。此外,您可以改爲從序列中設置主鍵。尋找SequenceImpl的例子,比你寫的要容易得多。 – MihaiC 2014-12-05 14:16:00
感謝您的建議! – Foswick 2014-12-05 19:54:59
我有你所描述的1-1視圖鏈接。但是,這並不會自動生成該孩子。我用來生成孩子的任何方法都無法自動填充FK。這似乎是由於孩子需要承諾才能找回其PK。第一眼看到你對序列的建議可以通過讓我主動設置PK來解決這個問題。我會仔細閱讀它,看看我能否整理出來。再次感謝。 – Foswick 2014-12-05 20:02:49