EclipseLinkでManyToManyのモデルを扱う

Pocket

JPA実装として人気だったHibernateですが、今後はEclipseLinkが主流になるらしい。
Hibernateつぶし? – ひがやすを blog

多対多のサンプルがWeb上に見つからなかったのでメモ。

[code lang=”ruby”]
CREATE TABLE IF NOT EXISTS `entries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`subject` varchar(255) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

CREATE TABLE IF NOT EXISTS `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`description` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS `categories_entries` (
`entry_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
PRIMARY KEY (`entry_id`,`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
[/code]

こんなテーブルがあったとすると、entriesとcategoriesに対応するエンティティにそれぞれ次のフィールドを追加する。

[code lang=”java”]
@Entity
@Table(name = "entries")
class Entry implements Serializable {
@ManyToMany
@JoinTable(name="categories_entries",
joinColumns={@JoinColumn(name="entry_id")},
inverseJoinColumns={@JoinColumn(name="category_id")})
private Set<Category> categories = new HashSet<Category>();
// アクセッサメソッドも必要
}

@Entity
@Table(name = "categories")
class Category implements Serializable {
@ManyToMany(mappedBy="categories")
private Collection<Entry> entries = new ArrayList<Entry>();
// アクセッサメソッドも必要
}
[/code]

以下で永続化インスタンスを取得。

[code lang=”java”]
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JavaApplication1PU");
EntityManager em = emf.createEntityManager();
Query q = em.createQuery("SELECT e FROM Entry e");
List<Entry> entries = q.getResultList();
Iterator<Entry> it = entries.iterator();
while (it.hasNext()) {
Entry entry = it.next();
logger.debug("id: {}", entry.getId());
logger.debug("subject: {}", entry.getSubject());
logger.debug("content: {}", entry.getContent());
Set<Category> categories = entry.getCategories();
Iterator<Category> itc = categories.iterator();
while (itc.hasNext()) {
Category category = itc.next();
logger.debug("category: {}", category.getName());
}
}
em.close();
emf.close();
[/code]

原因不明の病

一応これで動いたけど、SwingGUIアプリケーションだとタイミングによってなぜかエラーが出たり出なかったりする。まったく同じようなプロジェクトを作ったら何故かそっちはエラーが全く出ない。

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [SELECT e FROM Entry e]. Unknown entity type [Entry].
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1328)
at db.MyBlogSample.jButton1ActionPerformed(MyBlogSample.java:96)
at db.MyBlogSample.access$000(MyBlogSample.java:30)
at db.MyBlogSample$1.actionPerformed(MyBlogSample.java:57)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6267)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
at java.awt.Component.processEvent(Component.java:6032)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
at java.awt.Container.dispatchEventImpl(Container.java:2085)
at java.awt.Window.dispatchEventImpl(Window.java:2478)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: Exception [EclipseLink-8034] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Error compiling the query [SELECT e FROM Entry e]. Unknown entity type [Entry].
at org.eclipse.persistence.exceptions.JPQLException.entityTypeNotFound(JPQLException.java:483)
at org.eclipse.persistence.internal.jpa.parsing.ParseTreeContext.classForSchemaName(ParseTreeContext.java:138)
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.getClassOfFirstVariable(SelectNode.java:327)
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.getReferenceClass(SelectNode.java:316)
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.getReferenceClass(ParseTree.java:439)
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.adjustReferenceClassForQuery(ParseTree.java:79)
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.populateReadQueryInternal(JPQLParseTree.java:103)
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.populateQuery(JPQLParseTree.java:84)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:202)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:173)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:125)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:109)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1326)
... 28 more

一筋の光

一旦生成物を削除して実行したら直った。Javaは何故かこういうことが多いので注意が必要。

蛇足

JPA 2.0を使う場合はJava6推奨らしい。

投稿者紹介

株式会社ユニキャスト
私たちは、テクノロジに魅せられた個性あふれるメンバーによって構成された茨城県日立市に本社を構えるベンチャー企業です。
”テクノロジを通して「驚き」と「感動」を創造し、人々の「夢」と「笑顔」を支えます。” の経営理念をモットーに明るい未来を描き、ワクワクする企画提案を続けて参ります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください