6

我有 2 个实体,比如 Car 和 Engine(只是示例名称,但逻辑是相同的)。

@Entity
public class Car {
    @Id
    private Long id;

    @OneToOne(mappedBy = "car", cascade = Cascade.ALL)
    private Engine engine;
    ...


}

@Entity
public class Engine {
    @Id
    private Long id; // 1

    @MapsId // 2
    @OneToOne
    @JoinColumn(name = "car_id") // join column is optional here
    private Car car;
    ...
} 

所以,然后我做:

em.save(car); // successfully saved, data is in the database, but (see below)
TypedQuery<Engine> query = em.createQuery("select engine from Engine engine where engine.car = :car", Engine.class)
query.setParameter("car", car);

query.getResultList();

抛出异常:

ERROR [main] (JDBCExceptionReporter.java:234) - No value specified for parameter 1.
 WARN [main] (TestContextManager.java:409) - Caught exception while allowing TestExecutionListener     [org.springframework.test.context.transaction.TransactionalTestExecutionListener@17e5cbd] to process 'after' execution for test: method , exception [org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.DataException: could not execute query; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.DataException: could not execute query]

但是,如果我将引擎实体更改为在汽车实例本身上只有 @Id(删除 //1 并将 //2 更改为 @Id)它可以工作。

根据 JPA 文档,它应该以相同的方式工作(至少我预期)。

我的环境:PostgreSQL 9、Spring framework 3.1、Hibernate 3.6.8.Final、Tomcat 7(JPA 支持由 Spring 工具添加)。

更新:我已经用 EclipseLink 尝试了这两种映射并且它有效。所以问题可能出在Hibernate的某个地方。仍然不知道如何强制它与 Hibernate 一起工作。

4

1 回答 1

6

我假设您正在使用基于此的 Engine 类中的复合键的 Id。@MapsId 仅在您有 @EmbeddedId 时使用,如下例所示。

如果依赖实体使用嵌入的 id 表示其主键,则关系属性对应的嵌入 id 中的属性必须与父实体的主键类型相同,并且必须由应用到的 MapsId 注解指定关系属性。

@Embeddable
public class DependentId {
  String name;
  long empPK; // corresponds to PK type of Employee
}
@Entity
public class Dependent {
  @EmbeddedId DependentId id;
...
// id attribute mapped by join column default
  @MapsId("empPK") // maps empPK attribute of embedded id
  @ManyToOne Employee emp;
}

根据您的代码示例。

 @Embeddable
    public class NewKey{
      private Long id;
      private Long carId; // corresponds to PK type of Employee
    }

@Entity
public class Car {
    @Id
    private Long id;

    @OneToOne(mappedBy = "car", cascade = Cascade.ALL)
    private Engine engine;
}

@Entity
public class Engine {
    @EmbeddedId NewKey id;

    @MapsId("carId") // 2
    @OneToOne
    @JoinColumn(name = "car_id") // join column is optional here
    private Car car;
    ...
} 

假设您尝试使用关系的父键作为新键

如果依赖实体只有一个主键属性(即关系属性或关系属性对应的属性)且父实体的主键是简单主键,则依赖实体的主键是简单主键与父实体类型相同的主键(未指定 EmbeddedId 和 IdClass)。在这种情况下,或者 (1) 关系属性被注释为 Id,或者 (2) 指定了单独的 Id 属性并且关系属性被注释为 MapsId(并且未指定 MapsId 注释的 value 元素)。

在这种情况下,您的配置应该可以正常工作,如下所示,这是使用 hibernate 4.3 测试的

在此处输入图像描述

于 2014-04-19T07:34:22.610 回答