2013-04-30 50 views
1

內關係我有三個@PC類:GAE數據存儲區不會存留資1:1嵌入JDO

@PersistenceCapable 
class A { 
    @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
    @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true") 
    private String     id; 

    @Persistent @Embedded 
    private B b; 

    public void setB(B b){ 
    this.b=b; 
    } 
} 

@PersistenceCapable @EmbeddedOnly 
class B { 
    @Persistent 
    private String someInfo; 
    @Persistent 
    private C c; 

    public void setC(C c){ 
    this.c=c; 
    } 
} 

@PersistenceCapable 
class C { 
    @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
    @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true") 
    private String     id; 

    @Persistent 
    private String value; 

    public void setValue(String value){ 
    this.value=value; 
    } 
} 

我想要實現的是乙同時保持到C的引用被保存到相同的實體甲但GAE不讓我,我坐上以下異常承諾:

Detected attempt to establish A(1) as the parent of C(2) but the entity identified by C(2) has already been persisted without a parent. A parent cannot be established or changed once an object has been persisted. 

在此代碼:

A a = new A(); 
B b = new B(); 
C c = new C(); 
c.setValue("foo"); 
b.setC(c); 
a.setB(b); 

m.makePersistent(a); 

此外:查看DatastoreViewer顯示C已被保留!但是A不見了。這可能發生,因爲我不明確地回滾事務異常,在這種情況下是不相關的,但顯示C寫在它的父A之前。

我在想什麼? TX

更新2:

的建議我已經明確地啓用事務:

Transaction tx = pm.currentTransaction(); 
try { 
    tx.begin(); 
    pm.makePersistent(a); 
    tx.commit(); 
} finally { 
    if (tx.isActive()) { 
    tx.rollback(); 
    } 
    pm.close(); 
} 

相同的異常被拋出W/O明確的事務做.makePersistent()時。然後我設置禁用全球跨在JDO配置TX選項:

<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="false"/> 

,現在得到一個不同的異常有可能暗示:

cross-group transaction need to be explicitly specified, see 
TransactionOptions.Builder.withXGfound both Element { 
    type: "A" 
    id: 1 
} 
and Element { 
    type: "C" 
    id: 2 
} 
+1

您能否顯示代碼嘗試保留您的數據? – skirsch 2013-04-30 10:27:52

+0

我已經更新了這個問題。我知道我不明確地使用該交易,但根據也應該起作用的Google文檔。 – comeGetSome 2013-04-30 11:19:14

+0

您向您的帖子中添加了「makePersistent」,但是...與*什麼對象*?當你打電話時,C的生命週期狀態是什麼?日誌告訴你所有這些東西 – DataNucleus 2013-04-30 12:32:00

回答

0

確定最後我得到了點,

但我認爲,數據存儲的JDO實現(我不知道,如果它的DataNucleus將工作)錯過了什麼事。根據transactions on DataStore通常只有沿着祖先的實體可以堅持一次,異常GAE 要求支持交叉組交易,這是由數量限制,但可以堅持不相關的實體路徑。兩者都不適用於我的情況。

解決方案現在是強制通過一個密鑰(GAE專有)無主的關係,這是唯一可能的kandidate來形容祖先路徑,使數據存儲得到它的權利是繼延伸到我的POJO:

class A { 
    ... 
    private String naturalPK; 
    public String getNaturalPK(){ 
    return naturalPK; 
    } 
    ... 
} 

class C { 
    ... 
    public void setId(String id){ 
    this.id=id; 
    } 
    ... 
} 

和持續性代碼:

tx.begin(); 

    // we have to assign parent/child keys to enforce ancestor path 
    Key parentKey = KeyFactory.createKey("A", A.getNaturalPK()); 
    a.setId(KeyFactory.keyToString(parentKey)); 

    // now build child key 
    a.getB().getC().setId(KeyFactory.createKeyString(parentKey, "C", A.getNaturalPK())); 

    pm.makePersistent(offerer); 
    tx.commit(); // works. 

一個問題是,我不能在這裏使用代理鍵,其他的事情是,我不希望非JDO和非BO代碼是在我的POJO,所以親子關係必須在JDO-DAO實現的某個地方建立。我猜想DataNucleus GAE端口在這裏做的有些不準確,因爲持久性圖看起來是相反的:)

0

我假設你的問題消失了,如果你設置了一個事務邊界爲此工作。雖然documentation聲稱你應該可以做,但我認爲你已經在你的jdoconfig.xml中設置了datanucleus.appengine.autoCreateDatastoreTxnstrue
因此,C存儲在它自己的事務中,並且包含它自己的實體組。在第二個交易,你存儲A,從而試圖重新分配C到禁止A的實體groupy:

,因爲在創建實體時

所以實體組只能分配:建立一個交易(按照建議)。

+0

謝謝,我檢查了它,但沒有成功(更新了我的問題) – comeGetSome 2013-04-30 20:15:46

+0

它可能有助於在事務建立後創建對象。 GAE/JDO組合有時關心有趣的細微差別...... – skirsch 2013-04-30 20:43:46