12
votes

I am having trouble getting @MapsId to work, despite following all the examples on the net.

Here is my the setup:

pom.xml:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>4.3.5.Final</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.31</version>
</dependency>

DDL scripts:

CREATE TABLE Subscription (
    id bigint not null primary key auto_increment,
    active boolean not null,
    maxNumUsers int not null
)ENGINE=InnoDB;

CREATE TABLE t.Project (
    name varchar(32) not null,
    subscriptionId bigint not null
)ENGINE=InnoDB;

ALTER TABLE t.Project ADD CONSTRAINT `projectPK` PRIMARY KEY (name, subscriptionId);
ALTER TABLE t.Project ADD CONSTRAINT `projectSubscriptionFK` FOREIGN KEY (subscriptionId) REFERENCES t.Subscription(id);

ProjectId.java:

@Embeddable
public class ProjectId implements Serializable {
    private Long subscriptionId;
    private String name;

Project.java:

@Entity
@Table(schema = "t")
public class Project {
    @EmbeddedId
    private ProjectId id;

    @ManyToOne
    @MapsId("subscriptionId")
    //@JoinColumn(name = "subscriptionId", referencedColumnName = "id", insertable = false, updatable = false)
    private Subscription subscription;

Subscription.java:

@Entity
@Table(schema = "t")
public class Subscription {

    @OneToMany(mappedBy = "subscription", cascade = CascadeType.ALL)
    private Map<ProjectId, Project> projects = new HashMap<>();

When I do an insert, the following error happens:

Hibernate: insert into t.Project (name, subscription_id) values (?, ?) 2014-07-20 11:06:59,193 org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1054, SQLState: 42S22 2014-07-20 11:06:59,193 org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Unknown column 'subscription_id' in 'field list'

...

... 94 more Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'subscription_id' in 'field list' at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:526) at com.mysql.jdbc.Util.handleNewInstance(Util.java:408) at com.mysql.jdbc.Util.getInstance(Util.java:383) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1062) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4226) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4158) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2840) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2082) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2334) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2262) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2246) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:187) ... 114 more

If I uncomment the @JoinColumn on Project.subscription and redeploy I get this error:

... 21 more Caused by: org.hibernate.MappingException: Repeated column in mapping for collection: t.Subscription.projects column: subscriptionId

I've also tried removing the @MapsId, I still get the repeated column error.

I am stumped as to how to get around this. Any suggestions would be appreciated.

Thanks


Update: If I make Subscription.projects a list instead of a map and I add the JoinColumn to project.subscription it works. However if I change subscription.projects back to a map, I start getting the org.hibernate.MappingException: Repeated column again. Obviously I would really like to use the Map so I'll keep digging.

3
What is your point of using @MapsId? What do you want to achieve?Maciej Dobrowolski
I have a one to many relationship where the many entity has a composite key containing the one entities id.Rian
I've also used AttributeOverride and AttributeOverride on the id field of project and in the ProjectId. Neither solve the problem.Rian

3 Answers

10
votes

When using the mapsId annotation you specify that the relationship shares and controls the field mapped by the Id mapping, so the field in the relationship mapping overrides the field in the Id mapping. This means that JPA will use the subscription_id default unless you specify the join column that you commented out:

@JoinColumn(name = "subscriptionId", referencedColumnName = "id")
7
votes

Ok, so the problem was that I needed to add @MapKey to subscription.projects otherwise it will complain with "org.hibernate.MappingException: Repeated column" when I add the @JoinColumn

Thanks for the suggestions

Here is the final code:

@Embeddable
public class ProjectId implements Serializable {
    private Long subscriptionId;
    private String name;

@Entity
@Table(schema = "t")
public class Project {
    @EmbeddedId
    private ProjectId id;

    @ManyToOne
    @MapsId("subscriptionId")
    @JoinColumn(name = "subscriptionId", referencedColumnName = "id", insertable = false, updatable = false)
    private Subscription subscription;


@Entity
@Table(schema = "t")
public class Subscription {

    @OneToMany(mappedBy = "subscription", cascade = CascadeType.ALL)
    @MapKey(name = "id")
    private Map<ProjectId, Project> projects = new HashMap<>();
1
votes

I think you need an @AttributeOverride to override the default join column name:

@EmbeddedId
@AttributeOverride(name="subscriptionId", column=@Column(name="subscriptionId"))
private ProjectId id;