【问题标题】:Embedded ID mapping fails with DescriptorException: There should be one non-read-only mapping defined for the primary key field (EclipseLink)嵌入式 ID 映射失败并出现 DescriptorException:应该为主键字段定义一个非只读映射 (EclipseLink)
【发布时间】:2021-02-13 20:59:20
【问题描述】:

我有以下非常简单的设计:

一个俱乐部有多个团队,每个团队都有一个团队类型代码(性别 - 年龄组代码)加上一个序数(团队)编号,例如20 岁以上的男性将是“MO20”,序号代表该年龄组的第一、第二等团队。这是Teams 的PK。你明白了。

俱乐部映射:

@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;

    ...
}

团队映射:

@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;

    ...
}

例外:

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 抱怨 Teams.club_id 的列映射:

There should be one non-read-only mapping defined for the primary key field [Teams.club_id].

但是为什么呢?

嵌入的 ID 字段或更确切地说是 ID 类在 clubId 字段上具有 @Column 而没有 insertable = true, updatable = true,因此它默认为可写,至少这是文档所说的:https://javaee.github.io/javaee-spec/javadocs/javax/persistence/Column.html#insertable--

因此,所有其他 club_id 映射必须为 insertable = true, updatable = true 才能为只读,例如 Team.club 关系。

问题

这里有什么问题?

请注意,当在 Team.clubTeamPk.clubId 之间切换 insertable = ..., updatable = ... 时,整个事情都会起作用。

为什么 EclipseLink 在这里阻塞?对我来说似乎是一个错误。

PS:我使用的是 EclipseLink 2.7.7。 (hibernate标签只是为了吸引更多关注)

【问题讨论】:

    标签: hibernate jpa eclipselink jpa-2.0


    【解决方案1】:

    通过将@MapsId("clubId") 放在关联上,您是在说“clubId 是否提供自己的映射。相反,这里应该使用此属性上的映射来映射clubId 属性'。

    这意味着当持久化实体时,Eclipselink 将使用Team.club 的 id 来填充 club_id 连接列,然后,它将使用该连接列的值来填充 Java 属性 Team.embeddedId.clubId,每当获取/刷新实体时。 您在Team.embeddedId.clubId 上放置的任何映射都将被忽略

    这个错误来自于 Eclipselink 不认为club_id 被映射两次。相反,只考虑Team.club 上的映射。作为主键属性的唯一映射,它可能不是insertable = false, updatable = false

    解决方法很简单:

    1. 如果您希望Team.club 控制club_id 列的值,请删除insertable = false, updatable = false
    2. 相反,如果您希望Team.embeddedId.clubId 控制club_id,则完全放弃@MapsId

    【讨论】:

    • 您描述的行为是 JPA 规范定义的还是 EclipseLink 所做的,例如历史上?我在文档等的任何地方都找不到@MapsId 的行为方式,请参阅javaee.github.io/javaee-spec/javadocs/javax/persistence/…。文档通常直接从规范中提取句子。这个(虽然你可能仍然是对的)没有提到你所描述的任何事情。
    • '指定一个 ManyToOne 或 OneToOne 关系属性,为 EmbeddedId 主键中的一个属性提供映射(...)'实际上是我在答案的第一段中描述的
    • 我真的理解正好相反:“@MapsId("clubId") 告诉映射器将此关系映射到嵌入 ID 的 clubId”。与可写性/只读无关。只是列/秒。从那以后我在@MapsId 上遇到了麻烦。也许你是对的,只要接受你写的。 @MapsId 是所有 JPA 注释中最令人毛骨悚然的 - 或者更确切地说是文档中的第一句话。
    猜你喜欢
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 2013-11-22
    相关资源
    最近更新 更多