Reputation: 14003
I have the following very simple design:
A club has multiple teams, and each team having a team type code (a gender - age group code) plus an ordinal (team) number, e.g. MALE OVER 20 would be "MO20", with the ordinal number representing the 1st, 2nd etc. team for that age group. This is the PK for the Teams
. You get the point.
Club mappings:
@Entity
@Table(name = "Clubs")
public class Club implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column
private Integer id;
@Basic(optional = false)
@Column
private String name;
@Basic(optional = false)
@Column
private String code;
@OneToMany(mappedBy = "club")
private List<Team> teams;
...
}
Team mappings:
@Entity
@Table(name = "Teams")
public class Team implements Serializable
{
private static final long serialVersionUID = 1L;
@EmbeddedId
private TeamPk embeddedId;
@MapsId("clubId")
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "club_id", insertable = false, updatable = false)
private Club club;
...
}
@Embeddable
public class TeamPk implements Serializable
{
private static final long serialVersionUID = 1L;
@Column(name = "club_id")
private Integer clubId;
@Column(name = "team_type_code")
private String teamTypeCode;
@Column(name = "ordinal_nbr")
private Integer ordinalNbr;
...
}
Exception:
Caused by: Exception [EclipseLink-28019] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Deployment of PersistenceUnit [BBStatsPU] failed. Close all factories for this PersistenceUnit.
Internal Exception: Exception [EclipseLink-0] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.IntegrityException
Descriptor Exceptions:
---------------------------------------------------------
Exception [EclipseLink-46] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: There should be one non-read-only mapping defined for the primary key field [Teams.club_id].
Descriptor: RelationalDescriptor(net.bbstatstest.i265.entity.Team --> [DatabaseTable(Teams)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.exceptions.EntityManagerSetupException.deployFailed(EntityManagerSetupException.java:241)
... 182 more
Caused by: Exception [EclipseLink-0] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.IntegrityException
Descriptor Exceptions:
---------------------------------------------------------
Exception [EclipseLink-46] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: There should be one non-read-only mapping defined for the primary key field [Teams.club_id].
Descriptor: RelationalDescriptor(net.bbstatstest.i265.entity.Team --> [DatabaseTable(Teams)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:762)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:698)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:629)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:868)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:811)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:256)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:772)
... 180 more
EclipseLink complains about the column mappings for Teams.club_id
:
There should be one non-read-only mapping defined for the primary key field [Teams.club_id].
But why?
The embedded ID field or rather the ID class in place has @Column
on the clubId
field without insertable = true, updatable = true
, so it defaults to being writable, at least that's what the docs say: https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Column.html#insertable--
Hence all other club_id
mappings must be insertable = true, updatable = true
to be read-only, like the Team.club
relationship.
QUESTION:
What's wrong here?
Note, that the whole thing works when switching the insertable = ..., updatable = ...
between Team.club
and TeamPk.clubId
.
Why is EclipseLink choking here? Looks like a bug to me.
PS: I'm using EclipseLink 2.7.7. (hibernate
tag only added to attract more attention)
Upvotes: 0
Views: 414
Reputation: 10716
By putting @MapsId("clubId")
on the association, you're saying 'clubId
does not provide its own mapping. Instead, the mapping on this property here should be used to map the clubId
property'.
This means that when persisting the entity, Eclipselink will use Team.club
's id to populate the club_id
join column, and then, it will use the value of that join column, to populate the Java property Team.embeddedId.clubId
, whenever the entity is fetched/refreshed. Whatever mapping you put on Team.embeddedId.clubId
will be ignored.
The error comes from the fact that Eclipselink does not consider club_id
to be mapped twice. Instead, only the mapping on Team.club
is taken into account. Being the only mapping for a primary key property, it may not be insertable = false, updatable = false
.
The solution is simple:
Team.club
to control the value of the club_id
column, drop the insertable = false, updatable = false
Team.embeddedId.clubId
to control club_id
, drop @MapsId
altogetherUpvotes: 1