Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to query with @MapsId and @Id, but works just with @Id

Tags:

java

jpa

jpql

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.

like image 627
Aliaksandr Kazlou Avatar asked Jul 28 '12 05:07

Aliaksandr Kazlou


1 Answers

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

enter image description here

like image 152
Koitoer Avatar answered Oct 14 '22 05:10

Koitoer