Java 无法使用GAE/J DataNucleus插件版本2.1.2获取新创建的JDO持久实体的ID
我的问题 我正在使用新的1.7.5 GAE/J SDK将我的应用程序从1.x版移植到2.0版的DataNucleus插件for GAE/J。这将我的JDO版本从2.3更改为3.0.1。我的持久实体类有一个编码字符串类型的主键,以及对对象数字ID的只读访问。每个实例都是其实体组的唯一成员(子实例和父实例仅通过数字ID链接) 以前,我已经能够创建并持久化一个新的Java 无法使用GAE/J DataNucleus插件版本2.1.2获取新创建的JDO持久实体的ID,java,google-app-engine,google-cloud-datastore,jdo,datanucleus,Java,Google App Engine,Google Cloud Datastore,Jdo,Datanucleus,我的问题 我正在使用新的1.7.5 GAE/J SDK将我的应用程序从1.x版移植到2.0版的DataNucleus插件for GAE/J。这将我的JDO版本从2.3更改为3.0.1。我的持久实体类有一个编码字符串类型的主键,以及对对象数字ID的只读访问。每个实例都是其实体组的唯一成员(子实例和父实例仅通过数字ID链接) 以前,我已经能够创建并持久化一个新的MyEntity实例,然后立即访问其数字ID以存储在父MyEntity实例的子ID列表中 现在,我发现新实例的数字ID在持久化之后并不立即可
MyEntity
实例,然后立即访问其数字ID以存储在父MyEntity
实例的子ID列表中
现在,我发现新实例的数字ID在持久化之后并不立即可用——即使它是生成和存储的,并且在以后可用
我的问题
在对象创建和持久化之后,我是否可以立即恢复对数字ID的访问
“jdoconfig.xml”配置提取
<persistence-manager-factory name="big-table">
<property
name="javax.jdo.PersistenceManagerFactoryClass"
value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"
/>
<property name="datanucleus.DetachAllOnCommit" value="true"/>
<property name="javax.jdo.option.NontransactionalRead" value="true"/>
<property name="javax.jdo.option.NontransactionalWrite" value="true"/>
<property
name="datanucleus.appengine.autoCreateDatastoreTxns"
value="true"
/>
[...]
</persistence-manager-factory>
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class MyEntity implements Serializable
{
private static final long serialVersionUID = 1L;
// No setter for this read-only data member
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String sEncodedKey;
// No setter for this read-only data member
@Persistent
@Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
private Long loID;
@Persistent
private Long loParentID;
//
// Other persistent data members
//
public Long getID()
{
return loID;
}
//
// Other getters and setters
//
}
24-Feb-2013 13:28:02 [...].MyEntityBusiness createMyEntityChild
FINE: Pre-commit: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:03 [...].MyEntityBusiness createMyEntityChild
FINE: Post-commit: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:03 [...].MyEntityBusiness createMyEntityChild
FINE: Post-pm-close: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:07 com.google.appengine.api.datastore.dev.LocalDatastoreService$PersistDatastore persist
INFO: Time to persist datastore: 141 ms
包含3个记录点的持久性代码
/**
* Create a new entity.
* @param loParentID
* The ID of the entity,
* a new child of which is to be created.
* @param sChildName
* The name of the new child to be created.
* @return
* The created entity child,
* or <code>null</code> if the operation was carried out unsuccessfully.
*/
public static MyEntity createEntityChild(Long loParentID, String sChildName)
{
MyEntity meResult = null;
MyEntity mePersistedChild = null;
PersistenceManagerFactory pmf =
DataExchange.getPersistenceManagerFactory(); // My own method
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try
{
tx.begin();
MyEntity meChild = new MyEntity();
meChild.setParentID(loParentID);
meChild.setName(sChildName);
meChild.setActive(true);
mePersistedChild = pm.makePersistent(meChild);
// "Touch" data member not in the default fetch group
ArrayList<Long> liChildIDs = mePersistedChild.getChildIDs();
if (liChildIDs != null)
liChildIDs.size();
if (mePersistedChild != null)
g_logger.log(Level.FINE, String.format(
"Pre-commit: mePersistedChild.getID() = %d,"
+ " mePersistedChild.getEncodedKey() = \"%s\".",
mePersistedChild.getID(), mePersistedChild.getEncodedKey()));
tx.commit();
if (mePersistedChild != null)
g_logger.log(Level.FINE, String.format(
"Post-commit: mePersistedChild.getID() = %d,"
+ " mePersistedChild.getEncodedKey() = \"%s\".",
mePersistedChild.getID(), mePersistedChild.getEncodedKey()));
}
finally
{
try
{
if (tx.isActive()) // Because of an exception, say
tx.rollback();
}
finally
{
pm.close();
}
}
if (mePersistedChild != null)
g_logger.log(Level.FINE, String.format(
"Post-pm-close: mePersistedChild.getID() = %d,"
+ " mePersistedChild.getEncodedKey() = \"%s\".",
mePersistedChild.getID(), mePersistedChild.getEncodedKey()));
[...]
return meResult;
}
开发服务器日志记录输出
<persistence-manager-factory name="big-table">
<property
name="javax.jdo.PersistenceManagerFactoryClass"
value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"
/>
<property name="datanucleus.DetachAllOnCommit" value="true"/>
<property name="javax.jdo.option.NontransactionalRead" value="true"/>
<property name="javax.jdo.option.NontransactionalWrite" value="true"/>
<property
name="datanucleus.appengine.autoCreateDatastoreTxns"
value="true"
/>
[...]
</persistence-manager-factory>
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class MyEntity implements Serializable
{
private static final long serialVersionUID = 1L;
// No setter for this read-only data member
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String sEncodedKey;
// No setter for this read-only data member
@Persistent
@Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
private Long loID;
@Persistent
private Long loParentID;
//
// Other persistent data members
//
public Long getID()
{
return loID;
}
//
// Other getters and setters
//
}
24-Feb-2013 13:28:02 [...].MyEntityBusiness createMyEntityChild
FINE: Pre-commit: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:03 [...].MyEntityBusiness createMyEntityChild
FINE: Post-commit: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:03 [...].MyEntityBusiness createMyEntityChild
FINE: Post-pm-close: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:07 com.google.appengine.api.datastore.dev.LocalDatastoreService$PersistDatastore persist
INFO: Time to persist datastore: 141 ms
JDO增强版本验证
生成过程成功,输出片段为:
datanucleusenhancer:
09:33:00,531 (main) INFO [DataNucleus.Enhancer] - DataNucleus Enhancer for API "JDO"
09:33:01,125 (main) INFO [DataNucleus.Enhancer] - DataNucleus Enhancer (version 3.1.1) : Enhancement of classes
DataNucleus Enhancer (version 3.1.1) : Enhancement of classes
09:33:03,281 (main) INFO [DataNucleus.Enhancer] - Writing class file "[Path]\MyEntity.class" with enhanced definition
[... (N entries in all)]
09:33:04,046 (main) INFO [DataNucleus.Enhancer] - DataNucleus Enhancer completed with success for [N] classes. Timings : input=1922 ms, enhance=984 ms, total=2906 ms. Consult the log for full details
DataNucleus Enhancer completed with success for [N] classes. Timings : input=1922 ms, enhance=984 ms, total=2906 ms. Consult the log for full details
软件环境
<persistence-manager-factory name="big-table">
<property
name="javax.jdo.PersistenceManagerFactoryClass"
value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"
/>
<property name="datanucleus.DetachAllOnCommit" value="true"/>
<property name="javax.jdo.option.NontransactionalRead" value="true"/>
<property name="javax.jdo.option.NontransactionalWrite" value="true"/>
<property
name="datanucleus.appengine.autoCreateDatastoreTxns"
value="true"
/>
[...]
</persistence-manager-factory>
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class MyEntity implements Serializable
{
private static final long serialVersionUID = 1L;
// No setter for this read-only data member
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String sEncodedKey;
// No setter for this read-only data member
@Persistent
@Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
private Long loID;
@Persistent
private Long loParentID;
//
// Other persistent data members
//
public Long getID()
{
return loID;
}
//
// Other getters and setters
//
}
24-Feb-2013 13:28:02 [...].MyEntityBusiness createMyEntityChild
FINE: Pre-commit: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:03 [...].MyEntityBusiness createMyEntityChild
FINE: Post-commit: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:03 [...].MyEntityBusiness createMyEntityChild
FINE: Post-pm-close: mePersistedChild.getID() = null, mePersistedChild.getEncodedKey() = "agttYXJrZXQtdHJlZXISCxIMSXRlbUNhdGVnb3J5GAUM".
24-Feb-2013 13:28:07 com.google.appengine.api.datastore.dev.LocalDatastoreService$PersistDatastore persist
INFO: Time to persist datastore: 141 ms
- Web服务器:适用于Java 1.7.5版的Google应用程序引擎
- Web框架:ApacheWicket 6.5.0
- Java版本:1.6.0_39;Java热点(TM)客户端VM 20.14-b01
- GAE/J DataNucleus插件版本:2.1.2
- DataNucleus访问平台版本:3.1.3
- JDO版本:3.0.1
- 操作系统:在x86上运行的Microsoft Windows XP 5.1版
- IDE:NetBeans 7.2(构建201207171143)
JDO提供,您可以很容易地设置postStore回调,并在对象中设置一些字段(并且不依赖于特定于AppEngine的“功能”)。受@DataNucleus评论的启发,我以一种模糊不清的类似精神做了一项工作。下面列出的工作对我来说是可行的,但我发现我的根本问题仍然存在 所有使用编码键字符串的(只读)数字ID的持久实体都需要更改其
getID()
方法以使用变通方法
Java代码
我将我的ID getter方法(前面给出)修改如下:
public Long getID()
{
Long loResult = DataExchange.getIDFromEKSIfIDIsNull(loID, sEncodedKey);
return loResult;
}
我的DataExchange
类具有新方法:
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
/**
* Get the ID supplied, or get it from the encoded key string if the ID is
* <code>null</code>.
* <br/>
* This method is necessary since JDO version 3.0.1 introduces a long delay
* between entity first persistence and ID availability using the DataNucleus
* GAE primary key ID plug-in.
* @param loID
* The persistent entity ID.
* This may be <code>null</code> if the entity has been persisted for the
* first time but its generation is delayed (a big hello to JDO version
* 3.0.1).
* @param sEncodedKey
* The persistent entity encoded key string.
* This should be not <code>null</code> if the entity has been persisted.
* @return
* <ul>
* <li>
* If the persistent entity ID supplied is not <code>null</code>
* then return it
* </li>
* <li>
* else if the encoded key string is not <code>null</code> then extract
* the ID and return it
* </li>
* <li>
* else return <code>null</code>.
* </li>
* </ul>
*/
public static Long getIDFromEKSIfIDIsNull(Long loID, String sEncodedKey)
{
Long loResult = null;
if (loID != null)
loResult = loID;
else if (sEncodedKey != null)
{
Key key = KeyFactory.stringToKey(sEncodedKey);
if (key != null)
{
long loIDFromEKS = key.getId();
loResult = Long.valueOf(loIDFromEKS);
}
}
return loResult;
}
谢谢你的回答。我将更新此线程,了解我的进展。感谢您提供有关生命周期侦听器的提示。遗憾的是,在我的
StoreLifecycleListener\postStore(InstanceLifecycleEvent事件)
中,使用PersistenceCapable 35; jdoGetObjectId()
返回的ID是编码的键字符串,而不是它的数字ID(我所追求的)。我在以下位置提出了GAE问题8925(保存后无法立即获取编码的密钥字符串主键ID):。错误的问题跟踪器(谷歌也没有回复),显然,您可以通过使用EntityUtils.getKeyForObject获得密钥(以及数字)。。。当然,您必须提取ExecutionContext(通过将PM转换为JDOperationResistenceManager等),但这样做很容易,非常感谢。我在DataNucleus AppEngine上提出了问题314(保存后无法立即获得带有“DataNucleus gae.pk ID”的编码密钥字符串主键ID),该问题的位置为:。我将更新这个线程,告诉你我是如何处理你的代码提示的。(我还将询问有关重新公布DataNucleus AppEngine问题跟踪程序的事宜。