我有三个@PC课程:
@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;
}
}
我想实现B持有与A相同的实体,同时持有对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();
}
当执行.makePersistent()没有显式事务时抛出相同的异常。然后我在JDO config中设置了禁用全局交叉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
}
答案 0 :(得分:0)
如果您为此设置了事务边界,我认为您的问题就会消失。虽然documentation声称您应该可以执行的操作,但我认为您已在datanucleus.appengine.autoCreateDatastoreTxns
中将true
设置为jdoconfig.xml
。
因此,C
与其自己的实体组一起存储在自己的事务中。在第二个交易中,您存储了A
,因此尝试将C
重新分配给A
的被禁止的实体组:
因为实体组只能在创建实体时分配
所以:设置一个交易(按照推荐)。
答案 1 :(得分:0)
好的,我明白了,
然而我认为DataStore的JDO实现(我不知道它的DataNucleus作业是否会遗漏)。根据{{3}},通常只有祖先的实体可以一次性保留,特别是GAE 声明以支持跨组事务,这些事务受数量限制但可以保持不相关的实体路径。两者都不适用于我的情况。
穷人解决方案现在通过密钥(GAE专有)强制执行无主关系,这是描述祖先路径的唯一可能的kandidate,以便DataStore正确地跟随我的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端口在这里有些不准确,因为持久性图看起来是相反的:)