Грааль-многие-многие ассоциации и предотвращение каскада - PullRequest
3 голосов
/ 03 ноября 2010

Итак, у нас есть отношение «многие ко многим» между Customer и Role, настроенное как:

Customer {
  static hasMany = [roles: Role]
}

Role {
  static hasMany = [customer: Customer]
  static belongsTo = Customer
}

У объекта Role есть только имя и набор разрешений.Мы не хотим каскадно сохранять данные из Customer -> Role, поскольку Role следует изменять только напрямую.

Я добавил:

static mapping = {
  roles cascade: 'none'
}

, но всякий раз, когда я создаю клиента,Таблица ролей также обновляется.Ничего не меняется, за исключением того, что номер версии увеличивается.

Я что-то упускаю, что нужно установить ... есть ли ошибка в том, как в Grails установлены отношения "многие ко многим" и каскады ...... или есть какой-то другой способ, которым я могу предотвратить обновление ролей каждый раз?

1 Ответ

5 голосов
/ 03 ноября 2010

Обычно я сопоставляю таблицу соединений как класс домена, чтобы избежать этой и других проблем (производительность загрузки коллекции, ошибки оптимистической блокировки и т. Д.). Это включает удаление hasMany и belongsTo и создание класса домена CustomerRole:

import org.apache.commons.lang.builder.HashCodeBuilder

class CustomerRole implements Serializable {

   Customer customer
   Role role

   boolean equals(other) {
      if (!(other instanceof CustomerRole)) {
         return false
      }

      other.customer?.id == customer?.id &&
         other.role?.id == role?.id
   }

   int hashCode() {
      def builder = new HashCodeBuilder()
      if (customer) builder.append(customer.id)
      if (role) builder.append(role.id)
      builder.toHashCode()
   }

   static CustomerRole get(long customerId, long roleId) {
      find 'from CustomerRole where customer.id=:customerId and role.id=:roleId',
         [customerId: customerId, roleId: roleId]
   }

   static CustomerRole create(Customer customer, Role role, boolean flush = false) {
      new CustomerRole(customer: customer, role: role).save(flush: flush, insert: true)
   }

   static boolean remove(Customer customer, Role role, boolean flush = false) {
      CustomerRole instance = CustomerRole.findByCustomerAndRole(customer, role)
      instance ? instance.delete(flush: flush) : false
   }

   static void removeAll(Customer customer) {
      executeUpdate 'DELETE FROM CustomerRole WHERE customer=:customer', [customer: customer]
   }

   static void removeAll(Role role) {
      executeUpdate 'DELETE FROM CustomerRole WHERE role=:role', [role: role]
   }

   static mapping = {
      id composite: ['customer', 'role']
      version false
      table 'customer_roles'
   }
}

Блок отображения настраивает сгенерированный DDL так, чтобы он был таким же, как у вас сейчас, поэтому вам не нужно вносить какие-либо изменения в базу данных.Статические вспомогательные методы не требуются, но их удобно скрывать в процессе предоставления и отзыва ролей.

Вам нужно будет изменить свой код.Поскольку нет hasMany, вы не можете использовать customer.addToRoles(...).Вместо этого для предоставления роли просто создайте новый экземпляр CustomerRole, используя метод create, а для отзыва удалите экземпляр, используя метод remove.

Обновленный класс роли будет

class Role {
}

и обновленный класс Customer будет иметь вид

class Customer {
   Set<Role> getRoles() {
      CustomerRole.findAllByUser(this).collect { it.role } as Set
   }
}

У этого есть удобный метод getRoles(), который имитирует коллекцию roles, созданную для вас hasMany, поскольку вам все еще понадобится простой способдля доступа к предоставленным ролям клиента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...