Tomcat 6 で GWT (2.5.0)、Hibernate (JPA フレーバーあり) を使用する完全に機能する Web アプリケーションがあります。このアプリケーションを変換して、Google App Engine (GAE) (私は 1.7.6 を持っています) で実行したいと考えています。 . GAE は DataNucleus を使用しており、Hibernate から JDO または JPA のいずれかに変換する必要があり (私は既にモデルに JPA を使用していたので後者を選択しました)、EntityManager を使用するため、地獄が始まります。
から、 become 、 becomeHibernate Session
への変換を行いました。その後に、become 、 become などを追加する必要がありました。問題はマッピングに伴います。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/other リレーションで 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.
私が抱えている主な懸念の 1 つは、上記を使用してデータストアにクエリを実行するにはどうすればよいかということです。たとえば、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 があります)。
public static 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();
初めて正常に動作し(0でない場合のみordinal
...明らかに0が好きではありません)、データベースに aと aレコードkeyId
の両方を作成し、 LogType type_id の値は. 10 が実際のログ ID で、11 が実際の LogType ID だと思います。毎回テーブルをクリアするので、テーブルの 11 番目のエントリではないことに注意してください。各テーブルには 1 つのレコードしかありません。LogType
Log
Log(10)/LogType(11)
上記のコードを (テーブルをクリアせずに) 2 回目に呼び出すと、次のようになります。
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
2 回目は、myLog 内に含まれる LogType INFO に id (エンコードされた文字列) が含まれていることに注意してください。これは、最初の実行から既に格納されているためです。
これを検索しましたが、エラーまたは解決策を説明するものは何も見つかりませんでした。同じ LogType で別のログを書きたくないようです。何か案は?
読んでくれてありがとう!