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.
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<>();
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")
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