Нужно ли назначать отношения Grails hasOne в обоих направлениях? - PullRequest
7 голосов
/ 03 июня 2011

Должен ли я назначить отношения в каждом направлении?Используя классы домена учебника для отношения hasOne , в моем тестировании пока что необходимо, чтобы экземпляры распознавали друг друга:

def face = new Face()
def nose = new Nose()
face.nose = nose
nose.face = face

Не знаю почему, хотя,И это необычно неловко.Я ожидаю, что есть лучший способ.

РЕДАКТИРОВАТЬ:

Мне нужна помощь с отношениями назначение .Мне не нужна информация о механизме установки отношения hasOne в классах предметной области или дискуссии о целесообразности двунаправленных ссылок.Я хочу знать, почему для установки взаимосвязи между экземпляром носа и экземпляром лица требуется больше, чем один оператор .

Мое решение с двумя утверждениями основано на проблемах, с которыми я сталкиваюсьв сложном приложении.Я попытаюсь воспроизвести мой опыт на простом примере.

1 Ответ

17 голосов
/ 03 июня 2011

Прямой ответ

Необходимость установить отношения, т. Е. Назначать нос лицу и лицо узлу, не очень неудобна.Hibernate - это маппер RELATIONSHIP , поэтому вы должны сделать отношения явными.Тем не менее, вы можете написать меньше кода, определив

setNose(nose){
   this.nose = nose
   nose.face = this
}

на Face.Теперь, когда вы делаете face.nose = nose, для вас вызывается сеттер, и отношения устанавливаются так, как вы хотите.

Общие полезные мысли

Как правило, вам не нужно назначать отношения в обоих направлениях.Вполне допустимо иметь однонаправленные или двунаправленные отношения.

Однако определение hasOne имеет очень специфические значения.В документации очень четко говорится, что цель hasOne - указать hibernate поместить ключ, который определяет отношения в дочернем объекте, в данном случае Nose.Если вы внимательно об этом подумаете, вы поймете, что отношения должны быть двунаправленными.Вот некоторые мысли:

1) вы определяете hasOne на Face (то есть родитель).
2), даже если вы определили hasOne для родителя, базовая таблица, на которую влияют, является дочерней.таблица (т. е. столбец face_id на Nose)
3) Поскольку внешний ключ находится на дочернем элементе, дочерний элемент должен иметь ссылку на своего родителя.Если это не так, у вас будет дочернее свойство, которое является внешним ключом, но не связано с объектом.
4) Помните, что вы используете механизм ORM для определения отношений.Хотя вы можете вручную добавить поле face_id в Nose и настроить значения в коде (т. Е. Самостоятельно управлять отношениями, а не позволять инструменту ORM делать это), тот факт, что вы используете ORM в явном виде, означает, что инструмент ORM будет управлять отношениямидля вас.

РЕДАКТИРОВАТЬ - теперь, читая мой ответ, я не был убежден, поэтому я написал тест.Я определил классы Face и Nose, как показано в документации hasOne, но не определил Face на носу.Я пытался сделать это однонаправленным.Я написал тест, чтобы увидеть, что произойдет.Вот тест

class FaceTests extends GroovyTestCase {

    public void testStuff(){
        Face face = new Face()
        Nose nose = new Nose()

        face.nose = nose;
        face.save(flush:true)

        assertNotNull face.id
        assertNotNull nose.id
    }

}

, и результатом является исключение, содержащее

hasOne property [Face.nose] is not bidirectional. Specify the other side of the relationship!

. Таким образом, фреймворк даже гарантирует, что при использовании hasOne у вас будет двунаправленныйотношения.

...