2012-07-28 48 views
2

我有2个实体,比如汽车和引擎(只是示例名称,但逻辑相同)。无法使用@MapsId和@Id进行查询,但只能使用@Id

@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.springframew[email protected]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框架3.1,Hibernate 3.6.8.Final,Tomcat 7(JPA支持被Spring Instrumentation添加)。

更新: 我已经试过的EclipseLink既映射和它的工作。所以问题可能与Hibernate有关。仍然不知道如何强制它与Hibernate一起工作。

+0

如果删除JoinColumn会发生什么?同时拥有JoinColumn和MapsId似乎是矛盾的。第一个说:使用专用列,第二个说:使用与ID相同的列。 – 2012-07-28 06:10:57

+0

什么都不会发生。这种情况下的JoinColumn是可选的,它用于为\ @Id字段设置\ @Column。如果错过了,则默认使用默认的@JoinColumn,因此使用缺省的\ @JoinColumn中的@ @Id的默认列名。我真的觉得这可能是Hibernate中的错误,当然,当然,直到有人证明这一点。 – akazlou 2012-07-29 05:14:05

回答

2

我假设您正在使用基于该类的引擎类中的复合键的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是s pecified)。在这种情况下,或者(1) 关系属性被注释为Id,或者(2)指定单独的Id 属性并注释关系属性 MapsId(以及指定的MapsId注释的值元素不是 )。

在这种情况下,您的配置应该可以正常工作,您可以在下面看到,使用hibernate 4进行了测试。3

enter image description here