Как правильно управлять связанными объектами JPA с помощью двунаправленной связи OneToOne? - PullRequest
0 голосов
/ 04 марта 2019

Допустим, даны 2 сущности: основная и зависимая.

Они определяются в БД обычно как dependants.master_id -> masters.id, т.е. зависимая сущность содержит ссылку на основную сущность.

ВJPA one2one Двунаправленная ассоциация в этом случае обычно выглядит следующим образом:

class Master {
    @OneToOne(mappedBy="master")
    Dependant dependant
}
class Dependant {
    @OneToOne
    @JoinColumn("master_id")
    Master master
}

И этот подход вызывает необходимость иметь дело с обеими сторонами отношения, такими как:

Master master = new Master();
Dependant dependant = new Dependant();
dependant.setMaster(master);
master.setDependant(dependant);
repository.save(master);

вместо более интуитивного и более близкогок бизнес-логике, например:

Master master = new Master();
Dependant dependant = new Dependant();
master.setDependant(dependant);
repository.save(master);

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

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

У вас есть несколько вариантов, но все они зависят от правильной установки отношений на стороне владельца, которая в вашем случае равна Dependant.Лучший выбор для вас зависит от ваших потребностей и модели использования.Например, в другом ответе обсуждается определение метода @PrePersist, который может быть довольно чистым, если связь между Master и Dependent устанавливается тогда и только тогда, когда мастера сохраняются впервые.

Учитывая, что выиспользуя доступ на уровне поля, вы также можете подумать о том, чтобы Master.setDependant() выполнил работу за вас:

class Master {
    // ...

    @OneToOne(mappedBy="master")
    private Dependant dependant;

    public void setDependant(Dependant dep) {
        if (dep != null) {
            dep.setMaster(this);
        } else if (dependant != null) {
            // leaves a dangling dependant ...
            dependant.setMaster(null);
        }
        dependant = dep;
    }

    // ...
}

Это обеспечит, что при назначении Dependant для Master обратная связь будетавтоматически устанавливается на сторону Dependant.Затем вы захотите убедиться, что операции сохранения сохраняются для правильного каскадирования от Master до Dependant.

Обратите внимание, однако, что это не серебряная пуля.Это может легко, но на удивление потерпеть неудачу, если вы назначите отдельный или удаленный Dependant на Master.Скорее всего, он также потерпит неудачу, если вы попытаетесь заменить Master Dependant без явного удаления исходного, если таковой имеется.Есть и другие способы его сломать.

Поскольку управление отношениями всеми, кроме очень простых способов, требует тщательности и внимания к деталям, я бы посоветовал вам прикусить пулю и сделать это вручную, везде,если вам действительно нужно что-то большее, чем создание отношений, когда вы сохраняете новый Master и пересекаете существующие отношения.

0 голосов
/ 04 марта 2019

Один обходной путь может использовать @PrePersist.Для обеих сущностей вы можете реализовать такие методы, как:

Мастер

@PrePersist
private void prePersist() {
    if(null == getDependant().getMaster()) {
        getDependant().setMaster(this);
    }
}

Зависимый

@PrePersist
private void prePersist() {
    if(null == getMaster().getDependant()) {
        getMaster().setDependant(this);
    }
}

Или, может быть, простопропуская нулевые проверки.

...