Я использую JPA для определения модели данных для базы данных с составными ключами. Я не могу изменить базу данных.
У меня есть Car
сущность с составным ключом (carType и carId).
Второй (необязательный) объект PorscheInfo
содержит дополнительную информацию для автомобилей Porsche. К сожалению, соответствующая таблица "porsche_info" не содержит столбца, содержащего информацию carType, поскольку ее записи относятся исключительно к CarType = 'Porsche'
.
SQL для этой операции прост:
SELECT *
FROM cars
LEFT JOIN porsche_info
ON cars.CarId = porsche_info.CarId
AND cars.CarType = 'Porsche'
Как я могу перевести это в правильную настройку JPA?
Пока у меня есть следующие классы сущностей:
@Embeddable
public class CarKey {
private String carType;
private String carId;
}
@Entity(name = "cars")
public class Car {
@EmbeddedId
private CarKey key;
// car information
@OneToOne
@JoinColumn(name = "CarId", referencedColumnName = "CarId")
private PorscheInfo porscheInfo;
// or
@OneToMany
@JoinColumn(name = "CarId", referencedColumnName = "CarId")
private Set<PorscheInfo> porscheInfo;
}
@Embeddable
public class PorscheInfoKey {
private String carId;
}
@Entity (name = "porsche_info")
public class PorscheInfo {
@EmbeddedId
private PorscheInfoKey key;
// porsche info
}
Было бы предпочтительнее решение @OneToOne
, но решение @OneToMany
(из-за различных классов ключей) также является жизнеспособным.
CriteriaQuery выглядит так:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Car> carQuery = cb.createQuery(Car.class).distinct(true);
Root<Car> carRoot = carQuery.from(Car.class);
carQuery.select(carRoot);
carRoot.fetch("porscheInfo", JoinType.LEFT);
- В подходе
@OneToOne
я получаю:
org.hibernate.MappingException: повторяющийся столбец в сопоставлении для сущности: Car column: CarId (должен отображаться с помощью insert = "false" update = "false")
- В подходе
@OneToMany
я получаю:
org.hibernate.AnnotationException: referencedColumnNames (CarId) из PorscheInfo.porscheInfo, ссылающийся на Car, не сопоставленный с одним свойством
Как должна выглядеть правильная настройка JPA? Я не знаю, как сказать Hibernate, какие столбцы должны быть объединены. Я думал о .multiselect()
или Join<Car, PorscheInfo> ... .on()
подходах, но не заставил его работать.
редактирование:
Я получил @OneToOne
подход к работе с оговоркой:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CarId", referencedColumnName = "CarId", insertable = false, updatable = false)
private PorscheInfo porscheInfo;
Странное поведение: у всех автомобилей Porsche свойство porscheInfo
правильно инициализировано из-за carRoot.fetch("porscheInfo", JoinType.LEFT);
. Однако все автомобили не Porsche выдают исключение LazyInitializationException, когда я пытаюсь получить доступ к их свойству porscheInfo
. Стремительная выборка нежелательна, поскольку приводит к дополнительному ненужному запросу для каждого автомобиля (1 + N запросов).