2

Grails で多対多の関係を持つ 2 つのドメイン クラスがあります: デッキとカードです。

セットアップは次のようになります。

class Deck {
static hasMany = [cards: Card]
}

class Card {
static hasMany = [decks: Deck]
static belongsTo = Deck
}

デッキを削除した後、デッキに属さないカードもすべて削除したいです。これを実現する最も簡単な方法は、次の sql のようなものを記述することです。

delete from card where card.id not in(select card_id from deck_cards);

ただし、結合テーブルであるdeck_cardsには対応するgrailsドメインクラスがないため、このSQLに解決されるHQLクエリを作成する方法がわかりません。HQL では delete ステートメントで結合を使用できないため、通常の結合を使用してこのステートメントを作成することはできません。また、サブクエリを使用してこの制限を回避すると、mySQL が文句を言います。サブクエリの「from」セクションで from を削除します。

また、休止状態の「delete-orphan」カスケード オプションを使用してみましたが、その結果、デッキが削除されると、それらのカードが他のデッキにも属している場合でも、すべてのカードが削除されます。私は夢中になっています - これは簡単な作業のようです。

編集 「デッキ」と「カード」のこの特定の使用法については、混乱があるようです。このアプリケーションでは、「カード」はフラッシュカードであり、デッキには何万枚もある可能性があります。また、ユーザーが必要に応じて編集できるように、デッキのコピーを作成する必要がある場合もあります。このシナリオでは、すべてのカードをコピーするのではなく、新しいデッキは古いデッキと同じカードを参照するだけで、カードが変更された場合にのみ新しいカードが作成されます。また、この削除は groovy のループで実行できますが、(上記の SQL を使用して) 1 つではなく数万の SQL 削除ステートメントが生成されるため、非常に遅く、リソースを大量に消費します。HQL で結合テーブルのプロパティにアクセスする方法はありませんか?

4

2 に答える 2

1

まず、あなたのエンティティの要点がわかりません。カードを複数のデッキに所属させることは非論理的です。belongToそして、 と の両方を持つことは非論理的hasManyです。

とにかく、削除にHQLを使用しないでください。

実際に が必要な場合はOneToMany、 を使用してをまたはsession.remove(deck)に設定します。cascadecardsREMOVEALL

本当に必要な場合は、エンティティに対してManyToMany手動でチェックを行ってください。疑似コードで(grailsを知らないため):

for (Card card : deck.cards} {
    if (card.decks.size == 0) {
        session.remove(card);
    }
}
于 2010-01-07T09:37:08.040 に答える
0

技術的な側面についてはお答えしませんが、モデルに挑戦します。これがあなたにとっても価値があることを願っています:-)


機能的には、2 つのオブジェクトのライフサイクルが同じではないように思えます。

  • デッキは変化しています: デッキは作成され、カードがいっぱいになり、変更され、削除されます。そうしないとコードを使用してそれらを再作成することができないため、データベースに永続化する必要があります。
  • カードは一定です: すべてのカードのセットは最初からわかっており、存在し続けます。データベースで一度カードを削除すると、後で誰かがそれをデッキに入れる必要があるときに同じカードを再作成する必要があるため、すべての場合において、可能なカードのリストを提供する責任を負うデータ構造があります。 . それらがデータベースに保存されていない場合は、それらを再作成できます...

あなたが与えたモデルでは、カードにはそれらを保持するデッキのセットがあります。しかし、その情報はデックの (変化する) ライフサイクルと同じライフサイクルを持っているので、デック側でのみ関連付けを保持することをお勧めします(一方向の多対多の関係)。

これで、カードは実際には一定の情報であるため、データベースに永続化する必要さえありません。(デックに加えて) 2 番目のテーブルがまだありますが、そのカード テーブルには、カードの識別情報のみが含まれます(「選択」する必要があるものに応じて、1 から 52 までの単純な整数、または 2 つの値になる可能性があります)。クエリで)、他のフィールドではありません(画像、強度、いくつかのポイントなど...)。


Hibernate では、これらの選択により、多対多の関係が値のコレクションに変わります( Hibernate リファレンスを参照)。

値のコレクションでは、カードはエンティティではなくコンポーネントです。また、それらを削除する必要はありません。すべてが Hibernate によって自動的に処理されます。

于 2010-01-07T09:37:21.520 に答える