I have 2 entities, say Car and Engine (just example names, but the logic is the same).
@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;
...
}
So, then I do:
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();
throws exception:
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]
However, if I change Engine entity to have only @Id on the car instance itself (removing //1 and changed // 2 to @Id) it works.
According to the JPA documentation it should work the same way (at least I expected).
My environment: PostgreSQL 9, Spring framework 3.1, Hibernate 3.6.8.Final, Tomcat 7 (JPA support is added by Spring instrumentation).
Update: I've tried both mappings with EclipseLink and it worked. So the problem is somewhere with Hibernate, probably. Still have no idea how I can force it to work with Hibernate.
I'm assume the Id you are working with composite keys in the Engine class based on that. @MapsId only is used when you have an @EmbeddedId, as the following example.
If the dependent entity uses an embedded id to represent its primary key, the attribute in the embedded id corresponding to the relationship attribute must be of the same type as the primary key of the parent entity and must be designated by the MapsId annotation applied to the relationship attribute.
@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;
}
As per your code example.
@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;
...
}
Assuming your tried to use the parent key of the relationship as your new key
If the dependent entity has a single primary key attribute (i.e, the relationship attribute or an attribute that corresponds to the relationship attribute) and the primary key of the parent entity is a simple primary key, the primary key of the dependent entity is a simple primary key of the same type as that of the parent entity (and neither EmbeddedId nor IdClass is specified). In this case, either (1) the relationship attribute is annotated Id, or (2) a separate Id attribute is specified and the relationship attribute is annotated MapsId (and the value element of the MapsId annotation is not specified).
In that case your configuration should work as you can see below, that was tested using hibernate 4.3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With