Вы не можете моделировать взаимоисключающие ассоциации с 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);
}
}