无法使用@MapsId和@Id进行查询,但只能使用@Id

时间:2012-07-28 05:14:39

标签: java jpa jpql

我有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]

但是,如果我将Engine实体更改为在car实例本身上只有@Id(删除// 1并将// 2更改为@Id),则可以正常工作。

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

我的环境:PostgreSQL 9,Spring框架3.1,Hibernate 3.6.8.Final,Tomcat 7(Spring工具添加了JPA支持)。

更新: 我已尝试使用EclipseLink进行映射,但它确实有效。所以问题可能在于Hibernate。仍然不知道如何强制它与Hibernate一起使用。

1 个答案:

答案 0 :(得分:2)

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

  

如果从属实体使用嵌入式id表示其主要ID   key,嵌入id中的属性对应的   relationship属性必须与主键的类型相同   父实体,必须由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;
    ...
} 

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

  

如果从属实体具有单个主键属性(即,   关系属性或对应的属性   关系属性)和父实体的主键是a   简单主键,从属实体的主键是a   与父实体相同类型的简单主键(和   既没有指定EmbeddedId也没有指定IdClass)。在这种情况下,要么(1)   relationship属性是带注释的Id,或者(2)单独的Id   指定了属性,并注释了关系属性   MapsId(以及MapsId注释的value元素不是   指定)。

在这种情况下,您的配置应该如下所示,使用hibernate 4.3进行测试

enter image description here