在 JPA Hibernate 中加入部分组合键

Max*_*Max 6 hibernate jpa one-to-one composite-key one-to-many

我正在使用 JPA 为具有复合键的数据库定义数据模型。我无法更改数据库。

我有一个Car带有复合键(carType 和 carId)的实体。第二个(可选)PorscheInfo实体包含保时捷汽车的附加信息。不幸的是,相应的“porsche_info”表不包含包含 carType 信息的列,因为其条目专门引用CarType = 'Porsche'

此操作的 SQL 很简单:

SELECT *
FROM cars
LEFT JOIN porsche_info
ON cars.CarId = porsche_info.CarId
    AND cars.CarType = 'Porsche'
Run Code Online (Sandbox Code Playgroud)

如何将其转换为正确的 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
}
Run Code Online (Sandbox Code Playgroud)

一个@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);
Run Code Online (Sandbox Code Playgroud)
  • @OneToOne方法中,我得到: org.hibernate.MappingException: Repeated column in mapping for entity: Car column: CarId (should be mapping with insert="false" update="false")
  • 在该@OneToMany方法中,我得到: org.hibernate.AnnotationException: referencedColumnNames(CarId) of 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;
Run Code Online (Sandbox Code Playgroud)

奇怪的行为是:porscheInfo由于carRoot.fetch("porscheInfo", JoinType.LEFT);. 但是,当我尝试访问它们的porscheInfo属性时,所有非保时捷汽车都会抛出 LazyInitializationException 。Eager fetching 是不可取的,因为它会导致对每辆车进行额外的不必要的查询(1+N 次查询)。