使用 Objectify 6 将文本类型放入数据存储
Put Text type to datastore with Objectify 6
我目前正在将项目的 DAO classes 从 JDO 实现迁移到 Objectify V6。
我的要求是确保在回滚的情况下可以使用旧版本的 DAO 加载由 Objectify 保存的实体。
在旧代码中,字符串存储为 Text
。如果我在实体定义中留下 Text
字段,Objectify 会将其作为 String
放入数据存储区(因为不再有 Text
类型)。
当前新的 DAO 实现不向后兼容,因为 ClassCastException
当 JDO 实现将 String 转换为 Text 类型时出现。
有没有办法使用 Objectify V6 将文本类型存储到数据存储?
我试图在实体定义中使用 String
而不是 Text
并创建一个 TranslatorFactory
来进行转换,但我无法找到正确的数据存储 Value
实现类型。
public class StringTextTranslatorFactory implements TranslatorFactory<String, Text> {
@Override
public Translator<String, Text> create(TypeKey<String> tk, CreateContext ctx, Path path) {
return new Translator<String, Text>() {
@Override
public String load(Value<Text> node, LoadContext ctx, Path path) throws SkipException {
Text text = node.get();
return text != null ? text.getValue() : "";
}
@Override
public Value<Text> save(String pojo, boolean index, SaveContext ctx, Path path)
throws SkipException {
return ???;
}
};
}
}
更新
该项目正在为 App Engine 数据存储区使用 JDO 2.3 的实现。该实现基于 DataNucleus 访问平台的 1.0 版。
数据实体定义如下:
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class CrmNote {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
@Persistent
private Text note;
}
堆栈跟踪:
java.lang.ClassCastException: java.lang.String cannot be cast to com.google.appengine.api.datastore.Text
at com.timzon.snapabug.server.data.CrmNote.jdoReplaceField(CrmNote.java)
at com.timzon.snapabug.server.data.CrmNote.jdoReplaceFields(CrmNote.java)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2772)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2791)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.fetchObject(DatastorePersistenceHandler.java:519)
at org.datanucleus.store.appengine.query.DatastoreQuery.entityToPojo(DatastoreQuery.java:649)
at org.datanucleus.store.appengine.query.DatastoreQuery.entityToPojo(DatastoreQuery.java:603)
at org.datanucleus.store.appengine.query.DatastoreQuery.access0(DatastoreQuery.java:119)
at org.datanucleus.store.appengine.query.DatastoreQuery.apply(DatastoreQuery.java:783)
at org.datanucleus.store.appengine.query.DatastoreQuery.apply(DatastoreQuery.java:774)
at org.datanucleus.store.appengine.query.LazyResult.resolveNext(LazyResult.java:94)
at org.datanucleus.store.appengine.query.LazyResult.resolveAll(LazyResult.java:116)
at org.datanucleus.store.appengine.query.LazyResult.size(LazyResult.java:110)
at org.datanucleus.store.appengine.query.StreamingQueryResult.size(StreamingQueryResult.java:130)
at org.datanucleus.store.query.AbstractQueryResult.toArray(AbstractQueryResult.java:399)
at java.util.ArrayList.<init>(ArrayList.java:178)
at com.timzon.snapabug.server.dao.CrmNoteDAO.getOrderedCrmNotes(CrmNoteDAO.java:27)
由 JDO post-编译 "enhancement" 添加的自动生成的 jdoReplaceField
方法中发生异常。我反编译了增强型 class,我看到数据存储对象直接转换为 Text
类型:
public void jdoReplaceField(int index) {
if (this.jdoStateManager == null) {
throw new IllegalStateException("state manager is null");
} else {
switch(index) {
case 0:
this.id = (Long)this.jdoStateManager.replacingObjectField(this, index);
break;
case 1:
this.note = (Text)this.jdoStateManager.replacingObjectField(this, index);
break;
default:
throw new IllegalArgumentException("out of field index :" + index);
}
}
}
因此,如果 note
字段作为 String
保存在数据存储中,那么在回滚的情况下将抛出 ClassCastException
。
无法使用 Objectify 6 使用的 Google 提供的 SDK 显式存储 Text
类型;只有 StringValue
。 Text
甚至不在罐子里。
不过,我认为这不重要。最终,两个 SDK(旧的应用引擎和新的)只是来回转换为 protobuf 结构。它们应该是兼容的。
特别奇怪,因为老低级API把字符串写进了Entity
结构; Text
仅当字符串超过一定长度时才需要。所以JDO应该处理String
。您的字符串字段上是否有某种特殊注释以强制它期望 Text
?该堆栈跟踪是什么样的?
我目前正在将项目的 DAO classes 从 JDO 实现迁移到 Objectify V6。 我的要求是确保在回滚的情况下可以使用旧版本的 DAO 加载由 Objectify 保存的实体。
在旧代码中,字符串存储为 Text
。如果我在实体定义中留下 Text
字段,Objectify 会将其作为 String
放入数据存储区(因为不再有 Text
类型)。
当前新的 DAO 实现不向后兼容,因为 ClassCastException
当 JDO 实现将 String 转换为 Text 类型时出现。
有没有办法使用 Objectify V6 将文本类型存储到数据存储?
我试图在实体定义中使用 String
而不是 Text
并创建一个 TranslatorFactory
来进行转换,但我无法找到正确的数据存储 Value
实现类型。
public class StringTextTranslatorFactory implements TranslatorFactory<String, Text> {
@Override
public Translator<String, Text> create(TypeKey<String> tk, CreateContext ctx, Path path) {
return new Translator<String, Text>() {
@Override
public String load(Value<Text> node, LoadContext ctx, Path path) throws SkipException {
Text text = node.get();
return text != null ? text.getValue() : "";
}
@Override
public Value<Text> save(String pojo, boolean index, SaveContext ctx, Path path)
throws SkipException {
return ???;
}
};
}
}
更新
该项目正在为 App Engine 数据存储区使用 JDO 2.3 的实现。该实现基于 DataNucleus 访问平台的 1.0 版。
数据实体定义如下:
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class CrmNote {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
@Persistent
private Text note;
}
堆栈跟踪:
java.lang.ClassCastException: java.lang.String cannot be cast to com.google.appengine.api.datastore.Text
at com.timzon.snapabug.server.data.CrmNote.jdoReplaceField(CrmNote.java)
at com.timzon.snapabug.server.data.CrmNote.jdoReplaceFields(CrmNote.java)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2772)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2791)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.fetchObject(DatastorePersistenceHandler.java:519)
at org.datanucleus.store.appengine.query.DatastoreQuery.entityToPojo(DatastoreQuery.java:649)
at org.datanucleus.store.appengine.query.DatastoreQuery.entityToPojo(DatastoreQuery.java:603)
at org.datanucleus.store.appengine.query.DatastoreQuery.access0(DatastoreQuery.java:119)
at org.datanucleus.store.appengine.query.DatastoreQuery.apply(DatastoreQuery.java:783)
at org.datanucleus.store.appengine.query.DatastoreQuery.apply(DatastoreQuery.java:774)
at org.datanucleus.store.appengine.query.LazyResult.resolveNext(LazyResult.java:94)
at org.datanucleus.store.appengine.query.LazyResult.resolveAll(LazyResult.java:116)
at org.datanucleus.store.appengine.query.LazyResult.size(LazyResult.java:110)
at org.datanucleus.store.appengine.query.StreamingQueryResult.size(StreamingQueryResult.java:130)
at org.datanucleus.store.query.AbstractQueryResult.toArray(AbstractQueryResult.java:399)
at java.util.ArrayList.<init>(ArrayList.java:178)
at com.timzon.snapabug.server.dao.CrmNoteDAO.getOrderedCrmNotes(CrmNoteDAO.java:27)
由 JDO post-编译 "enhancement" 添加的自动生成的 jdoReplaceField
方法中发生异常。我反编译了增强型 class,我看到数据存储对象直接转换为 Text
类型:
public void jdoReplaceField(int index) {
if (this.jdoStateManager == null) {
throw new IllegalStateException("state manager is null");
} else {
switch(index) {
case 0:
this.id = (Long)this.jdoStateManager.replacingObjectField(this, index);
break;
case 1:
this.note = (Text)this.jdoStateManager.replacingObjectField(this, index);
break;
default:
throw new IllegalArgumentException("out of field index :" + index);
}
}
}
因此,如果 note
字段作为 String
保存在数据存储中,那么在回滚的情况下将抛出 ClassCastException
。
无法使用 Objectify 6 使用的 Google 提供的 SDK 显式存储 Text
类型;只有 StringValue
。 Text
甚至不在罐子里。
不过,我认为这不重要。最终,两个 SDK(旧的应用引擎和新的)只是来回转换为 protobuf 结构。它们应该是兼容的。
特别奇怪,因为老低级API把字符串写进了Entity
结构; Text
仅当字符串超过一定长度时才需要。所以JDO应该处理String
。您的字符串字段上是否有某种特殊注释以强制它期望 Text
?该堆栈跟踪是什么样的?