Grails hasOne vs direct member variable
Скажем, у меня есть класс домена grails, который выглядит как
class Person {
Address address
}
Я мог бы также объявить его как
class Person {
static hasOne = [address:Address]
}
Второй способ переместил бы внешний ключ в таблицу Address, а не таблицу Person.
Каковы практические преимущества (или недостатки) в том, чтобы делать это одним способом против другого? Насколько я понимаю, они будут использовать внешние ключи, это просто вопрос о том, где живет внешний ключ.
Ответы
Ответ 1
Если внешний ключ существует в таблице адресов, то в этом адресе может быть только один человек.
Если внешний ключ находится в таблице лиц, у нескольких лиц может быть один и тот же адрес.
Это не о том, какой путь лучше/хуже. Это о том, что является правильным способом моделирования ваших данных.
Ответ 2
Я нахожу использование hasOne
в Grails, чтобы быть особенно запутанным. Например, в этом вопросе спрашивается, что происходит, когда отношение toOne объявляется следующим образом:
class Person {
static hasOne = [address: Address]
}
Как указано выше, это приводит к появлению внешнего ключа person_id
в таблице Address, что означает, что каждый адрес может указывать только на одного Person. То, что я нахожу причудливым, заключается в том, что, хотя код написан как "у человека есть один адрес", фактический результат состоит в том, что "адрес имеет одно лицо".
И на самом деле, как указано выше, нет ничего (на уровне базы данных), препятствуя тому, чтобы одна запись адреса указывала на одного и того же Лица, а это означает, что у Человека действительно нет одного адреса в конце концов.
Интересно, что вы получили бы такое же представление базы данных, если бы вы создали класс Address следующим образом:
class Address {
Person person
}
Внешний ключ person_id
будет находиться в таблице Address, как и в предыдущем примере, но, очевидно, вы не можете получить от Person в адрес в коде, не определяя эти отношения каким-либо образом.
Также интересно, что если вы моделировали отношения toMany от Person to Address в базе данных, вы использовали бы тот же макет таблицы. Вы поместили родительский первичный ключ (person_id) в дочернюю таблицу. С точки зрения базы данных, используя hasOne
, создается та же структура, что и отношения toMany.
Конечно, мы не просто создаем таблицы базы данных, мы создаем классы домена Grails, у которых есть какое-то поведение, связанное с ними, и некоторое применение семантики отношений. В этом конкретном бизнес-примере вы, вероятно, не хотите делиться одной и той же записью адресов с несколькими людьми, вы просто хотите сохранить адрес отдельно (возможно, готовясь к тому дню, когда у человека есть несколько адресов). Я бы, наверное, проголосовал за такой подход:
class Person {
Address address
static constraints = {
address unique:true
}
}
Внешний ключ address_id
будет находиться в таблице Person, а единственное ограничение будет гарантировать, что никакие две записи Person не указывают на тот же адрес.
Ответ 3
Я предлагаю следующее...
class Person {
...
static hasOne = [address: Address]
}
class Address {
...
static belongsTo = [person: Person]
}
Лицо имеет один адрес и адрес принадлежит одному лицу.
Таким образом, когда вы удаляете человека, адрес также будет удален, без проблем.
Я думаю, что это лучший способ сделать это.
Ответ 4
Лицо " hasOne" Адрес и адрес " принадлежит" Лицо.
Наличие внешнего ключа в таблице "child" имеет больше смысла, потому что таким образом ребенок будет разбиваться, если родитель отсутствует. Человек может существовать без его адреса, но "адрес лица" без человека не имеет смысла. Таким образом, адрес должен быть более слабой стороной отношений.
Выполняя это таким образом, в граалах обе сущности будут ссылаться друг на друга, чтобы он не чувствовал себя странно. Также каскадное поведение по умолчанию будет сохранять и удалять адрес при сохранении Лица, но если вы хотите удалить адрес, человек останется сохраненным.