Oleg Atamanenko
В данной заметке хочу поделиться некоторыми моментами использования GORM.
GORM - это ORM-фреймворк, используемый в Grails. Реализован он поверх Hibernate, но, при этом, с некоторыми отличными умолчаниями.
Для разработчиков, знающих Hibernate, рекомендую тщательно изучить GORM, так как его поведение в некоторых случаях отлично от Hibernate, что может приводить к различным сюрпризам.
По умолчанию GORM для связей один ко многим (one-to-many) создаёт таблицу-связку, которая обычно нужна только при связях между сущностями вида многие ко многим. Чтобы исправить это поведение необходимо указать GORM, чтобы он не создавал таблицу связку.
class Person implements Serializable {
static hasMany = [
scores: ScoreSheet
]
static mapping = {
scores joinTable: false
};
}
Если в приложении используются двунаправленные связи и вероятность изменения сущности одновременно несколькими пользователями высокая, то лучше использовать однонаправленные связи для сущностей. Кроме того, лучше проектировать доменные классы таким образом, чтобы связь была не один-ко-многим, а многие к одному.
class Note implements Serializable {
static belongsTo = [
person: Person
]
}
class Person implements Serializable {
// person fields.
}
Для работы с Notes необходимо использовать такие запросы:
Note.findByPerson(person).each { -> };
вместо
person.notes.each { -> }
GORM поддерживает только два варианта маппинга иерархии классов, в отличии от Hibernate: Таблица на всю иерархию (table-per-hierarchy), или таблица на каждый подкласс (table-per-subclass). У маппинга table-per-hierarchy есть серьёзный недостаток - подклассы не могут иметь ненулевые поля. Поэтому, если этот недостаток критичен, то необходимо использовать маппинг table-per-subclass.
class Payment {
Long id
Long version
Integer amount
static mapping = {
tablePerHierarchy false
}
}
class CreditCardPayment extends Payment {
String cardNumber
}