Google App Enginでぶち当たった問題 その2

最初に実装でぶつかった問題はJPAのコードの書き方。

GEAのJPAはDataNucleus Enhancer (version 1.1.0)を利用し無ければならないのだがコード作法があるようです。

サンプルですがアカウントの作成をするコードです。

public void addAccount(Account account) {
		EntityManager em = null;
		EntityTransaction tx = null;

		try {
			em = EMF.get().createEntityManager();
			tx = em.getTransaction();
			tx.begin();
			em.persist(account);
			tx.commit();
		} catch (Exception e) {
			if (em != null && tx != null) {
				if (tx.isActive()) {
					// TODO must implement Log
					System.out.println("Insert could not execute,  Rollbacking...");
					tx.rollback();
				}
			}
		} finally {
			em.close();
		}
	}

これは普通です。

でアカウントを削除する場合には

public void removeAccount(Account account) {
		EntityManager em = null;
		EntityTransaction tx = null;
		
		try {
			em = EMF.get().createEntityManager();
			tx = em.getTransaction();
			tx.begin();
			Account delete = em.find(Account.class, account.getAccountId());
			em.remove(delete);
			tx.commit();
		} catch (Exception e) {
			if (em != null && tx != null) {
				if (tx.isActive()) {
					// TODO must implement Log
					System.out.println("Remove could not execute,  Rollbacking...");
					tx.rollback();
				}
			}
		} finally {
			em.close();
		}
	}

これは普通です。

で検索を行う場合には

public Long findAccountByNickName(String nickname) {
		EntityManager em = null;
		EntityTransaction tx = null;

		List<Account> accounts = null;
		Long id = new Long(0);
		try {
			em = EMF.get().createEntityManager();
			tx = em.getTransaction();
			tx.begin();

			Query query = em.createQuery("SELECT a FROM Account"
					+ " a  WHERE a.accountName = ?1");	
			query.setParameter(1, nickname);
			accounts = (List<Account>) query.getResultList();
			tx.commit();
			if (accounts.equals(null)) {
				LOG.info("No record in account table");
			} else if (accounts.size() > 1) {
				LOG.info("duplicate record error in account table");
			} else {
				for (Account account : accounts) {
					id = account.getAccountId();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			em.close();
		}
		return id;

	}

とかいても動きません。

Query query = em.createQuery("SELECT a FROM " + Account.class.getName() + " a  WHERE a.accountName = ?1");

と書き直すと動きます。

たぶんテーブル構造がクラスに依存しているからでしょう・・

あとちょっとしたバグも発見しました。
プロジェクト名が info.hogehoge.gwt.... とかになると infoの部分はDataNucleus Enhancerがうまくパースできないようです。
http://code.google.com/p/datanucleus-appengine/issues/detail?id=35&can=1&q=info&colspec=ID%20Type%20Status%20Priority%20FoundIn%20TargetRelease%20Owner%20Summary
こちらに同じ問題がかいておりました。

JPAのテーブル構造を表すエンティティクラスでもははまりました。
エンティティクラスを作るときに @idをlong プリミティブ型を利用していたのですが、最初は全く気付かずはまりました・・Longのラッパーに変更しなければ動きません。

@Entity
public class Account {
	
	@Id
	@GeneratedValue(strategy = IDENTITY)
	private Long accountId;
	private String accountName;
	private String email;
	private String gender;
	private Date registDate;
	private Date birthDay;


//以下setter getter----

次回はJunitでテストを行う際に戸惑った問題を書きます。