GORMのMany-to-Manyの動作とドキュメントの差異について

29 views
Skip to first unread message

k-kuwana

unread,
Oct 22, 2013, 5:18:04 AM10/22/13
to jg...@googlegroups.com
皆さん。
こんにちわ。桑名と申します。

掲題の件なのですが、GORMのMany-to-Manyのドキュメントと実際の動作に関して確認させていただきたいことがあります。

該当ドキュメントは以下です。
http://grails.jp/doc/latest/guide/GORM.html#manyToMany

サンプルでは、BookとAuthorというドメインを用意していて、正しく動作する場合と動作しない場合のコードを示していますが、正しく動作しない方の説明として、

--------------------------------------------------------------------------------------
しかし、これはBookだけが保存されauthorsは保存されません!
However this will only save the Book and not the authors!
--------------------------------------------------------------------------------------

と記述されています。
しかし、子側のBookだけ保存されるのって動作としてどうなの?と思って実際にコードを流してみたところ、AuthorもBookもデータは保存されませんでした。
確認は、grails shellで実際にサンプルコードを実行して行いました。
実行結果はnullが返ってきました。正しく動作する方のコードは
===> grailssamples.Author : 1
がちゃんと帰ってきています。

この動作自体が本来そもそも正解で、ドキュメントの方の説明が誤っているのかな?と思っているのですが、なにか私の思い違いなどありますでしょうか?

確認環境:
Windows7(64bit)
Grails version: 2.2.3
Groovy Shell (2.0.8, JVM: 1.7.0_21)
MySQLServer version: 5.1.41


以上、よろしくお願いいたします。

Yasuharu NAKANO

unread,
Oct 22, 2013, 5:28:19 AM10/22/13
to jg...@googlegroups.com
中野です。

これは、翻訳と言うより原文の言い回しがアレなのと、サンプルの説明が足りてない、という問題な気がしますね。

まず確認された動作は正しいです。それが仕様です。
belongsToを書いた方が所有される子側になります。カスケードは親から子に対して行われるので、Author→Bookへのカスケードだけが有効ですよ、というのが正しいです。

好意的に考えてたぶん元々言いたかったことは、
「(Authorからのカスケードでbooksとしての)Bookは保存できるけど、(Bookからのカスケードで)authors(としてのAuthor)は保存されません!」
で、Book側でsaveしている2つめのサンプルはもっと「こっちは動きませんよ」アピールをしなければならなかった感じです。

そもそも関連部分はややこしいのに説明が分かりづらすぎる(というか理解するの無理な)ので、本家の方に反映するようにしておきますね。
フィードバックありがとうございます。



2013/10/22 k-kuwana <saba...@gmail.com>

--
このメールは Google グループのグループ「JGGUG」の登録者に送られています。
このグループから退会し、メールの受信を停止するには、jggug+un...@googlegroups.com にメールを送信します。
このグループに投稿するには、jg...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/jggug からこのグループにアクセスしてください。
その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。



--
Yasuharu NAKANO / nobeans

Yasuharu NAKANO

unread,
Oct 22, 2013, 6:02:12 AM10/22/13
to jg...@googlegroups.com
あ、一点見逃していました。

> AuthorもBookもデータは保存されませんでした。
> 実行結果はnullが返ってきました。

save()の戻り値がnullになるというのはバリデーションエラーですね。保存に*失敗*してます。
よくよくみたら、Bookのくせにnameプロパティ使ってます。titleの誤りですね。
サンプルコードのバグです...。併せてフィードバックかけておきます。

仕様としては、Book→AuthorはカスケードしないのでBookだけがsaveされる、が正しいです。
Author→Bookはカスケードによって両方保存されます。



2013/10/22 Yasuharu NAKANO <yn...@jggug.org>

k-kuwana

unread,
Oct 22, 2013, 8:55:39 AM10/22/13
to jg...@googlegroups.com
中野さん

ありがとうございます!
そしてすみませんでした・・・まさかコードが間違っているだけとは・・・。もっと査読するべきでした。

当初の疑問の「子側だけで保存ができるのはどうなの?」という点に関して、そもそもなぜそんな疑問に至ったかというと、多対1の場合、以下のコードが考えられます。

---------------------------------------------------------------
class Author {
    String name
    Book book
    static constraints = {
    }
}

class Book {
    String title
    static belongsTo = [author:Author]
    static constraints = {
    }
}
---------------------------------------------------------------

この状態だと、子側(Book)のみの保存が出来ませんでした。
そのため、belongsToを指定すると、子側のみでは保存・削除は出来なくなるのだな、と思い込んでしまっていました。
ちなみにこの場合、Book側のconstraintsを、
static constraints = {
    author blank: true, nullable: true
}
にすると、子側(Book)のみで保存が出来ることを確認しました。
ちなみにconstraintsを付けなかった場合のエラーの内容は下記のとおりです。

groovy:000> > book.errors.allErrors.each{println it}
book.errors.allErrors.each{println it}
Field error in object 'grailssamples.Book' on field 'author': rejected value [null]; codes [grailssamples.Book.author.nullable.error.grailssamples.Book.author,grailssamples.Book.author.nullable.error.author,grailssamples.Book.author.nullable.error.grailssamples.Author,grailssamples.Book.author.nullable.error,book.author.nullable.error.grailssamples.Book.author,book.author.nullable.error.author,book.author.nullable.error.grailssamples.Author,book.author.nullable.error,grailssamples.Book.author.nullable.grailssamples.Book.author,grailssamples.Book.author.nullable.author,grailssamples.Book.author.nullable.grailssamples.Author,grailssamples.Book.author.nullable,book.author.nullable.grailssamples.Book.author,book.author.nullable.author,book.author.nullable.grailssamples.Author,book.author.nullable,nullable.grailssamples.Book.author,nullable.author,nullable.grailssamples.Author,nullable]; arguments [author,class grailssamples.Book]; default message [Die Eigenschaft [{0}] des Typs [{1}] darf nicht null sein]
===> [Field error in object 'grailssamples.Book' on field 'author': rejected value [null]; codes [grailssamples.Book.author.nullable.error.grailssamples.Book.author,grailssamples.Book.author.nullable.error.author,grailssamples.Book.author.nullable.error.grailssamples.Author,grailssamples.Book.author.nullable.error,book.author.nullable.error.grailssamples.Book.author,book.author.nullable.error.author,book.author.nullable.error.grailssamples.Author,book.author.nullable.error,grailssamples.Book.author.nullable.grailssamples.Book.author,grailssamples.Book.author.nullable.author,grailssamples.Book.author.nullable.grailssamples.Author,grailssamples.Book.author.nullable,book.author.nullable.grailssamples.Book.author,book.author.nullable.author,book.author.nullable.grailssamples.Author,book.author.nullable,nullable.grailssamples.Book.author,nullable.author,nullable.grailssamples.Author,nullable]; arguments [author,class grailssamples.Book]; default message [Die Eigenschaft [{0}] des Typs [{1}] darf nicht null sein]]
groovy:000> 


まだまだ勉強中ではありますが、GORMは複雑だな・・・というのが正直なイメージです。
複雑というよりも、今までORマッパーを使わずに逃げてきた自分にはなかなか厳しいといった方が正しいかも?

ググるとブログなどで素晴らしい記事は沢山あるのですが、中々チュートリアル的なものが見つからなくて大変です。
このまま調査を続けて、いつかGORMの逆引き資料みたいなのを作ってみたいなと思います。

ありがとうございました!



2013年10月22日 12:02 Yasuharu NAKANO <yn...@jggug.org>:

Yasuharu NAKANO

unread,
Oct 22, 2013, 10:09:51 AM10/22/13
to jg...@googlegroups.com
GORM複雑ですよね...。
ハッピーパス以外の挙動はRDBMSごとにも違ったりするので、更に悩ましいです。コーナーケースつつかなければいいんですけど。
インテグレーションテストとしてGORMの各種機能の学習テストを書いて挙動を抑えると、Grailsのアップグレード時にも挙動の違いがすぐ分かるし、忘れたら何度でも確認できるのでお勧めです。

> ググるとブログなどで素晴らしい記事は沢山あるのですが、中々チュートリアル的なものが見つからなくて大変です。
> このまま調査を続けて、いつかGORMの逆引き資料みたいなのを作ってみたいなと思います。

楽しみにしてます!



2013/10/22 k-kuwana <saba...@gmail.com>

Yasuharu NAKANO

unread,
Oct 22, 2013, 10:35:57 AM10/22/13
to jg...@googlegroups.com
補足です。

どうしてこうなるの?と分からなくなった場合は、生成されているスキーマを見てみると納得できることがよくあります。
説明しづらい挙動の場合、論理的な仕様としての挙動というよりも、スキーマ構造に伴う実装上の挙動なことも多いです。




2013/10/22 Yasuharu NAKANO <yn...@jggug.org>
Reply all
Reply to author
Forward
0 new messages