簡體   English   中英

在hql查詢中訪問聯接表以獲取Grails中的多對多關系

[英]Accessing the join table in a hql query for a many-to-many relationship in grails

我在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);

但是,我無法弄清楚如何編寫可解析為該SQL的HQL查詢,因為聯接表deck_cards沒有相應的grails域類。 我不能使用普通聯接編寫此語句,因為HQL不允許您在delete語句中使用聯接,並且如果我使用子查詢來解決此限制,則mySQL會抱怨,因為您不允許引用該表在子查詢的“ from”部分中刪除from。

我還嘗試了使用休眠的“刪除-孤立”級聯選項,但是即使刪除了牌組,即使這些卡也屬於其他牌組,也會導致所有卡都被刪除。 我快瘋了-這似乎應該是一個簡單的任務。

編輯對於“卡片組”和“卡片組”的這種特定用法,似乎有些困惑。 在此應用程序中,“卡片”是抽認卡,並且在一副牌組中可以有成千上萬張卡片。 另外,有時有必要制作卡座的副本,以便用戶可以根據需要對其進行編輯。 在這種情況下,新卡座不會復制所有卡,而是會引用與舊卡座相同的卡,並且如果僅更換卡,則會創建新卡。 另外,雖然我可以在groovy中循環執行此刪除操作,但它會非常緩慢且占用大量資源,因為它將生成數以萬計的sql delete語句,而不僅僅是生成1條(使用上述sql)。 是否無法訪問HQL中聯接表的屬性?

首先,我看不出您實體中的重點。 使一張卡屬於多個甲板是不合邏輯的。 同時擁有belongTohasMany是不合邏輯的。

無論如何,請勿使用HQL進行刪除。

如果您確實需要OneToMany ,請使用session.remove(deck)並將cardscascade設置為REMOVEALL

如果您確實需要ManyToMany ,請手動對實體進行檢查。 用偽代碼(因為我不知道grails):

for (Card card : deck.cards} {
    if (card.decks.size == 0) {
        session.remove(card);
    }
}

我不會回答技術方面的問題,但會挑戰模型。 我希望這對您也很有價值:-)


從功能上講,在我看來,您的兩個對象沒有相同的生命周期:

  • 卡片組在不斷變化 :它們已經創建,被卡片填充,被修改和刪除。 當然,它們必須保留到您的數據庫中,因為否則您將無法使用代碼來重新創建它們。
  • 卡是恆定的 :從一開始就知道所有卡的集合,它們一直存在。 如果您一次刪除了數據庫中的卡片,那么稍后當有人需要將其放置在Deck中時,您將需要重新創建同一張卡片,因此在所有情況下,您都將具有一個數據結構,負責提供可能的卡片列表。 如果它們沒有保存在數據庫中,則可以重新創建它們...

在您提供的模型中,卡片有一組放置卡片的甲板。 但是該信息的生命周期與Decks的生命周期相同(所以不斷變化),因此我建議僅在Deck一方 (單向多對多關系)保持關聯。

現在,您已經完成了工作,您的卡實際上是恆定的信息,因此甚至不需要將其持久化到數據庫中。 您仍然會有第二張表(除了Deck之外),但是Card表將僅包含Card的標識信息 (可以是1到52的簡單整數,也可以是兩個值,具體取決於您需要“選擇”什么)在您的查詢中),而不是其他字段(圖像,強度,某些點等)。


在Hibernate中,這些選擇將多對多關系轉換為值集合 (請參見Hibernate參考 )。

具有值的集合,Card不是實體而是組件。 而且您不必刪除它們 ,Hibernate會自動處理所有內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM