Каков наилучший способ реализации взаимоисключающих отношений в JPA? - PullRequest
0 голосов
/ 25 августа 2018

Я пытаюсь построить функциональную иерархию местоположений, и я начал с Страна модель / сущность. На один уровень ниже Провинция субъект с ManyToOne отношением к стране (двунаправленный). Теперь у меня есть Город сущность, которая ManyToOne привязана к Провинции (двунаправленная), но эта связь является недействительной. Но теперь, если отношения между городом и провинцией пусты, мне нужны отношения между городом и страной (также допускаемые значения). Так что требуется хотя бы один Но если один из этих двух уже установлен, другой ввести нельзя.

Таким образом, в принципе, эти два отношения в городе (город-провинция, город-страна) являются взаимоисключающими , но требуется как минимум одно из них. Я работаю с Java и JPA (Hibernate) , и я не нашел какой-либо специальной функциональности для реализации этого. Есть ли проверенный или "правильный" способ, как это сделать?

1 Ответ

0 голосов
/ 30 августа 2018

Вы не можете моделировать взаимоисключающие ассоциации с JPA или Hibernate.Но вы можете смоделировать 2 независимых и добавить ограничение BeanValidation.JPA интегрирует спецификацию BeanValidation и автоматически запускает проверку перед сохранением или обновлением и созданием сущности.

Я объяснил это более подробно в одном из моих советов по гибернации .Вот краткая форма.

Вы можете смоделировать 2 ассоциации на вашей City сущности.

@Entity
@EitherOr
public class City {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Version
    private int version;

    @ManyToOne
    private Province province;

    @ManyToOne
    private Country country;

    ...
}

Обратите внимание на аннотацию @EitherOr в строке 2. Это пользовательское ограничениечто я реализовал на основе спецификации BeanValidation.Аннотация @Constraint указывает ConstraintValidator, который будет запускаться при переходе жизненного цикла объекта.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {EitherOrValidator.class})
public @interface EitherOr {

    String message() default "A city can only be linked to a country or a province.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}

Реализация ConstraintValidator довольно проста.Вам необходимо реализовать метод isValid и убедиться, что атрибут province или country не равен нулю.

public class EitherOrValidator implements ConstraintValidator<EitherOr, City>{

    @Override
    public void initialize(EitherOr arg0) { }

    @Override
    public boolean isValid(City city, ConstraintValidatorContext ctx) {
        return (city.getProvince() == null && city.getCountry() != null) 
                || (city.getProvince() != null && city.getCountry() == null);
    }


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...