Граальс Многие для многих ассоциаций и предотвращения каскада
-
28-09-2019 - |
Вопрос
Итак, у нас есть многозначные отношения между клиентом и ролью, созданные как:
Customer {
static hasMany = [roles: Role]
}
Role {
static hasMany = [customer: Customer]
static belongsTo = Customer
}
Объект ролей имеет только имя и набор разрешений. Мы не хотим каскад экономит от клиента -> роли, как роль, как роль должна быть только изменена напрямую.
Я добавил:
static mapping = {
roles cascade: 'none'
}
Но всякий раз, когда я создаю клиента, таблита роли также обновляется. Ничто не изменяется, за исключением того, что номер версии увеличивается.
Я упучаю что-то еще, что нужно установить ... Есть ли ошибка с тем, как многие ко многим отношениям и каскадам устанавливаются в границах ... Или есть какой-то другой способ, которым я могу предотвратить обновление ролей каждый раз?
Решение
Я обычно сопоставляю таблицу присоединения в качестве класса домена, чтобы избежать этой проблемы и других (производительность загрузки сбора, оптимистичные ошибки блокировки и т. Д.) Это включает в себя удаление 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(...)
. Отказ Вместо этого для предоставления роли просто создать новый экземпляр usserrole, используя create
метод и отозвать, удалить экземпляр с использованием remove
метод.
Обновленный ролевый класс будет
class Role {
}
и обновленный класс клиентов будет
class Customer {
Set<Role> getRoles() {
CustomerRole.findAllByUser(this).collect { it.role } as Set
}
}
Это удобно метод getRoles()
которые имитируют roles
коллекция, созданная для вас hasMany
Поскольку вам все равно понадобится простой способ доступа к предоставленным клиентам ролях.