我有一个功能齐全的 Web 应用程序,它在 Tomcat 6 上使用 GWT(2.5.0)、Hibernate(具有 JPA 风格)。我现在想将此应用程序转换为在 Google App Engine (GAE) 上运行(我有 1.7.6) . GAE 使用 DataNucleus,一切都开始了,因为我必须从 Hibernate 转换为 JDO 或 JPA(我选择了后者,因为我已经将 JPA 用于我的模型),因此使用了 EntityManager。
我已经完成了从Hibernate Session
到的转换EntityManager
, Transaction
成为EntityTransaction
,beginTransaction()
成为getTransaction()
,我必须begin()
在它之后添加一个,saveOrUpdate
成为merge
,delete
成为remove
等等。问题来自映射。
在休眠中:
@Entity
@DiscriminatorValue("extend")
public class Admin extends User implements Serializable {
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name="admin_id")
@IndexColumn(name="users_index")
private List<User> users;
//...
}
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class User implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
protected long id;
@ManyToOne
@JoinColumn (name="admin_id", updatable = false, insertable = false)
private Admin admin;
//...
}
好吧,首先我不允许使用带有@OneToMany/@ManyToOne/其他关系的long(或Long)类型的id,所以我的选择是Key
编码字符串。Key
我不允许在 GWT 中使用(阅读有关 resmarksystems gwt jar 文件的信息,但这似乎是错误的做法/黑客,如果我错了,请纠正我)所以我认为编码字符串是要走的路:
@Entity
@DiscriminatorValue("extend")
public class Admin extends User implements Serializable {
@OneToMany(mappedBy="admin", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<User> users;
//...
}
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@MappedSuperclass //Had to add this or exception: Found inheritance strategy "new-table" on Admin. This strategy is not supported in this context. Please see the documentation for information on using inheritance with JPA: http://code.google.com/appengine/docs/java/datastore/usingjpa.html#Inheritance
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
protected String id;
@Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
protected Long keyId;
@ManyToOne
private Admin admin;
//...
}
这只会给我这些警告:
15:58:51,181 WARN [DataNucleus.MetaData] - Meta-data warning for Admin.users: Error in meta-data for Admin.users : The datastore does not support joins and therefore cannot honor requests to place related objects in the default fetch group. The field will be fetched lazily on first access. You can modify this warning by setting the datanucleus.appengine.ignorableMetaDataBehavior property in your config. A value of NONE will silence the warning. A value of ERROR will turn the warning into an exception.
15:58:51,182 WARN [DataNucleus.MetaData] - Meta-data warning for Admin.admin: Error in meta-data for User.admin : The datastore does not support joins and therefore cannot honor requests to place related objects in the default fetch group. The field will be fetched lazily on first access. You can modify this warning by setting the datanucleus.appengine.ignorableMetaDataBehavior property in your config. A value of NONE will silence the warning. A value of ERROR will turn the warning into an exception.
我的一个主要问题是,我将如何使用上述方法查询我的数据存储?例如,在 Hibernate 中,当我想获取给定管理员 (admin_id) 的所有用户时,我会执行以下操作:
Query queryResult = session.createQuery("from " + User.class.getName() + " where admin_id='" + id + "'");
使用编码字符串作为 id,我可以简单地做:
Query queryResult = em.createQuery("select from " + User.class.getName() + " where admin_id='" + id + "'");
图片在哪里keyId
出现?据我了解,您必须在我调用之前为其设置一个值,merge
或者persist
给定该值,生成我的编码字符串id
。我有这个权利吗?当我在对象的持久性之前设置它时,该值应该是什么?更新记录时是否必须提供不同的值?我可以为多条记录使用相同的 keyId 吗?我猜不是(鉴于以下代码)。
为了说明我的意思,假设以下内容:
@Entity
public class Log implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id; //can't use long or I get another exception here...
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(referencedColumnName="id")
private LogType type;
public Log(LogType type, Admin admin, String message, long timestamp) {
this();
this.type = type;
this.admin = admin;
this.message = message;
this.timestamp = timestamp;
}
//...
}
和
@Entity
public class LogType implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
protected String id;
@Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
protected Long keyId;
private String name;
public LogType(Long id, String name) {
this();
this.keyId = id;
this.name = name;
}
}
然后,假设我创建了一个新的 LogType(我有一个用于日志类型的枚举 LogTypeEnum):
公共静态 LogType INFO = new LogType(String.valueOf(LogTypeEnum.INFO.ordinal()), "INFO");
然后当我尝试在数据库中插入以下内容时:
Log myLog = new Log(INFO, admin, msg, System.currentTimeMillis());
tx.begin();
em.merge(myLog);
tx.commit();
第一次它工作正常(好吧,只有当不是ordinal
0 ... 我想 10 是我的实际日志 ID,而 11 是我的实际 LogType id。请注意,我每次都清除表格,因此它不是表格中的第 11 个条目。每张表只有一条记录。keyId
LogType
Log
Log(10)/LogType(11)
我第二次调用上面的代码(不清除表格),我得到:
javax.persistence.PersistenceException: Attempt to assign child with key "Log(10)/LogType(11)" to parent with key "Log(no-id-yet)". Parent keys are immutable
请注意,第二次,包含在 myLog 中的 LogType INFO 确实有一个 id(一个编码字符串),因为它在第一次运行时就已经存储了。
我对此进行了搜索,但没有发现任何解释错误或解决方案的内容。似乎它不想写另一个具有相同 LogType 的 Log。有任何想法吗?
非常感谢阅读!