Доступ к таблице соединений в hql-запросе для отношения многие ко многим в grails - PullRequest
2 голосов
/ 07 января 2010

У меня есть 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);

Однако я не могу понять, как написать HQL-запрос, который будет преобразован в этот SQL, потому что таблица соединений deck_cards не имеет соответствующего класса домена grails. Я не могу написать этот оператор, используя обычные объединения, потому что HQL не позволяет вам использовать объединения в операторах удаления, и если я использую подзапрос, чтобы обойти это ограничение, mySQL жалуется, потому что вы не можете ссылаться на таблицу удаление из раздела «из» подзапроса.

Я также пытался использовать спящий режим каскада «удалить-осиротить», но это приводит к удалению всех карт при удалении колоды, даже если эти карты также принадлежат другим колодам. Я схожу с ума - кажется, это должно быть простым заданием.

редактировать Кажется, есть некоторая путаница в этом конкретном использовании «колод» и «карт». В этом приложении «карты» - это карточки, и в колоде их может быть десятки тысяч. Кроме того, иногда необходимо сделать копию колоды, чтобы пользователи могли редактировать ее по своему усмотрению. В этом сценарии вместо того, чтобы копировать все карты, новая колода будет ссылаться на те же карты, что и старая колода, и если только карта будет заменена, будет создана новая карта. Кроме того, хотя я могу сделать это удаление в цикле в groovy, оно будет очень медленным и ресурсоемким, поскольку будет генерировать десятки тысяч операторов удаления sql, а не только 1 (используя вышеупомянутый sql). Нет ли способа получить доступ к свойству таблицы соединений в HQL?

Ответы [ 2 ]

1 голос
/ 07 января 2010

Во-первых, я не вижу смысла в ваших сущностях. Нелогично, чтобы карта принадлежала более чем одной колоде. И нелогично иметь как belongTo, так и hasMany.

В любом случае, не используйте HQL для удаления.

Если вам действительно нужен OneToMany, используйте session.remove(deck) и установите cascade из cards в REMOVE или ALL.

Если вы действительно хотите ManyToMany, выполните проверки вручную для сущностей . В псевдокоде (поскольку я не знаю Grails):

for (Card card : deck.cards} {
    if (card.decks.size == 0) {
        session.remove(card);
    }
}
0 голосов
/ 07 января 2010

Я не буду отвечать технической стороне, но буду оспаривать модель. Я надеюсь, что это также будет ценно для вас: -)


Функционально мне кажется, что у ваших двух объектов не одинаковый жизненный цикл:

  • Колоды меняются : они созданы, заполнены карточками, изменены и удалены. Они, безусловно, должны быть сохранены в вашей базе данных, потому что иначе вы не сможете воссоздать их, используя код.
  • Карты постоянны : набор всех карт известен с самого начала, они продолжают существовать. Если вы удаляете Карту один раз в базе данных, вам понадобится заново создать эту Карту позже, когда кому-то понадобится положить ее в колоду, поэтому во всех случаях у вас будет структура данных, которая отвечает за предоставление списка возможных Карт. , Если они не сохранены в вашей базе данных, вы можете воссоздать их ...

В модели, которую вы даете, у карт есть набор колод, которые их держат. Но эта информация имеет тот же жизненный цикл, что и колода (меняется), поэтому я предлагаю удерживать ассоциацию только на стороне колоды (однонаправленное отношение «многие ко многим»).

Теперь, когда вы это сделали, ваши Карты действительно содержат постоянную информацию, поэтому их даже не нужно сохранять в базе данных. У вас все еще была бы вторая таблица (в дополнение к колоде), но эта таблица карточек будет содержать только идентификационную информацию для карточки (может быть простым целым числом от 1 до 52 или двумя значениями, в зависимости от вам нужно «выбирать» в своих запросах), а не другие поля (изображение, сила, некоторые моменты и т. д.).


В Hibernate этот выбор превращает отношение «многие ко многим» в Набор значений (см. Ссылка на Hibernate ).

С набором значений, карта - это не сущность, а компонент. И вам не нужно удалять их , все автоматически обрабатывается Hibernate.

...