Tuesday, December 26, 2006

Grails Tips 一つのドメインクラスをManyToManyする方法


このブログを見ている人も増えつつあるので、
Tipsなんて物を書いてみようと思います。
本日の内容は、「一つのドメインクラスをManyToManyする方法」です。
いきなり、そこかよ・・と言われそうですが、いきなりそこからです。
普通は、簡単なことから始めた方が良いのかもしれませんが、
それだとTipsでは無くなるような気がして・・・

というわけで、開始です。

「一つのドメインクラスをManyToManyする方法」


例えば・・
Book は複数の Author を持つ
Author は複数の Book を持つ
Author は複数の Author を持つ
この場合、Authorが自分自身のAuthorを複数持つことになります。
Grailsデフォルトで、static hasMany = [ books : Book ,authors : Author ] と記述しても、動作しません。
さぁ、困った・・

そこで、hibernate.cfg.xmlと、Author.hbm.xmlの出番です。
Grailsでは、直接Hibernateをつかったドメインクラスのマッピングを行うことも可能です。
詳しくは、こちら

では、上記のリレーションを作成してみましょう。
まずは、ドメインクラスを用意します。

ドメインクラス:Book {grails-project}/grails-app/domain/Book.groovy

class Book {
static hasMany = [ authors : Author ]
static belongsTo = Author
String title

static constraints = {
}
}

ドメインクラス:Author {grails-project}/grails-app/domain/Author.groovy

class Author {
static hasMany = [ books : Book ,authors : Author ] // AuthorをhasManyする
def optionals = [ "authors","books" ]
String name

static constraints = {
}
}


次に、hibernate関連のファイルを作成します。
全て、 {grails-project}/hibernate/ に作成。
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping resource="Book.hbm.xml"/>
<mapping resource="Author.hbm.xml"/>
</session-factory>

</hibernate-configuration>

Author.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<hibernate-mapping>
<class name="Author" table="author">
<id name="id" column="id" unsaved-value="null">

<generator class="sequence">
<param name="sequence">author_author_id_seq</param>
</generator>
</id>

<version name="version" column="version" type="java.lang.Long"/>
<property name="name" column="name" />

<set name="books" table="author_book" lazy="true" inverse="false">

<key>
<column name="author_id" not-null="true"/>
</key>

<many-to-many class="Book">
<column name="book_id" not-null="true"/>
</many-to-many>

</set>
<set name="authors" table="author_author" lazy="true" inverse="false">

<key>
<column name="author_id" not-null="true"/>
</key>

<many-to-many class="Author">
<column name="author_m_id" not-null="true"/>
</many-to-many>

</set>
</class>
</hibernate-mapping>


Book.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="Book" table="book">
<id name="id" column="id" unsaved-value="null">

<generator class="sequence">
<param name="sequence">book_book_id_seq</param>
</generator>
</id>

<version name="version" column="version" type="java.lang.Long"/>
<property name="title" column="title"/>

<set name="authors" table="author_book" lazy="true" inverse="true">

<key>
<column name="book_id" not-null="true"/>
</key>

<many-to-many class="Author">
<column name="author_id" not-null="true"/>
</many-to-many>

</set>
</class>
</hibernate-mapping>


データ登録サンプル

def a1 = new Author(name:"one")
a1.save()
def a2 = new Author(name:"two")
a2.save()
def a3 = new Author(name:"tree")
a3.save()
def b = new Book(title:"wow")
b.add(to:"authors",a3)
b.save()

a1.add(to:"books",b)
a1.add(to:"authors",a2)
a1.add(to:"authors",a3)
a1.save()


.hbm.xmlを書いたドメインクラスと書いてないドメインクラスは混在もできるので、
必要に応じて.hbm.xmlを活用すると結構複雑なデータベース構造も構築可能のようです。



PS
さすが、欧州発のフレームワーク、クリスマス休暇はメーリングリストがおとなしいです。。

Labels: ,

0 Comments:

Post a Comment

<< Home