[英]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中聯接表的屬性?
首先,我看不出您實體中的重點。 使一張卡屬於多個甲板是不合邏輯的。 同時擁有belongTo
和hasMany
是不合邏輯的。
無論如何,請勿使用HQL進行刪除。
如果您確實需要OneToMany
,請使用session.remove(deck)
並將cards
的cascade
設置為REMOVE
或ALL
。
如果您確實需要ManyToMany
,請手動對實體進行檢查。 用偽代碼(因為我不知道grails):
for (Card card : deck.cards} {
if (card.decks.size == 0) {
session.remove(card);
}
}
我不會回答技術方面的問題,但會挑戰模型。 我希望這對您也很有價值:-)
從功能上講,在我看來,您的兩個對象沒有相同的生命周期:
在您提供的模型中,卡片有一組放置卡片的甲板。 但是該信息的生命周期與Decks的生命周期相同(所以不斷變化),因此我建議僅在Deck一方 (單向多對多關系)保持關聯。
現在,您已經完成了工作,您的卡實際上是恆定的信息,因此甚至不需要將其持久化到數據庫中。 您仍然會有第二張表(除了Deck之外),但是Card表將僅包含Card的標識信息 (可以是1到52的簡單整數,也可以是兩個值,具體取決於您需要“選擇”什么)在您的查詢中),而不是其他字段(圖像,強度,某些點等)。
在Hibernate中,這些選擇將多對多關系轉換為值的集合 (請參見Hibernate參考 )。
具有值的集合,Card不是實體而是組件。 而且您不必刪除它們 ,Hibernate會自動處理所有內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.