1

我有三个@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 在持有对 C 的引用的同时保持与 A 相同的实体,但 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 之前编写的。

我错过了什么?发送

更新 2:

正如建议的那样,我已明确启用事务:

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

与执行 .makePersistent() w/o 显式事务时抛出的异常相同。然后我在 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
}
4

2 回答 2

0

我假设如果您为此设置了事务边界,那么您的问题就会消失。尽管文档声称您应该可以执行此操作,但我假设您已datanucleus.appengine.autoCreateDatastoreTxns在. 因此,与它自己的实体组一起存储在它自己的事务中。在第二个事务中,您存储并尝试重新分配给' 的实体 groupy,这是被禁止的:truejdoconfig.xml
CACA

因为实体组只能在创建实体时分配

所以:建立一个事务(如推荐的那样)。

于 2013-04-30T15:37:16.003 回答
0

好的,我终于明白了,

但我认为 DataStore 的 JDO 实现(我不知道它的 DataNucleus 工作是否)错过了一些东西。根据DataStore 上的事务,通常只能一次性持久化沿祖先的实体,特别是 GAE声称支持受数量限制但可以持久不相关实体路径的跨组事务。两者都不适用于我的情况。

糟糕的解决方案现在是通过密钥(GAE 专有)强制执行无主关系,这是描述祖先路径的唯一可能的候选者,以便 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 端口在这里做的有点不准确,因为持久性图看起来是颠倒的:)

于 2013-04-30T21:28:24.780 回答