@OneToMany @MapKeyColumn 关系的可写性映射假定在@Id 字段上
Writability mapping of @OneToMany @MapKeyColumn relationship assumed to be on @Id field
我有一个游戏实体,它通过 Map
+ @MapKeyColumn
引用两个分数,其中一个实体用于主队,一个用于客队:
我决定使用 Boolean
列 is_home
来解决这个问题。我映射了 @MapKeyColumn
关系 而没有 insertable = false, updatable = false
,使关于 is_home
列的注释可写。
由于每列可能只有一个可写 field/annotation,我不得不将 insertable = false, updatable = false
添加到 Score
实体上的 @Id
映射,字段 home
,见下文。
游戏:
@Entity
@Table(name = "Games")
public class Game implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column
private Integer id;
@Basic(optional = false)
@Column(name = "scheduled_tipoff")
private LocalDateTime scheduledTipoff;
@OneToMany(mappedBy = "game")
@MapKeyColumn(name = "is_home") <- writable
private Map<Boolean, Score> scores;
...
}
得分:
@Entity
@Table(name = "Scores")
@IdClass(ScoreId.class)
public class Score implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "is_home", insertable = false, updatable = false) <- not writable
private Boolean home;
@Basic
@Column(name = "final_score")
private Integer finalScore;
@Id
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "game_id")
private Game game;
...
}
分数:
public class ScoreId implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer game;
private Boolean home;
...
}
这导致使用 EclipseLink 时出现异常:
异常
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-28013] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Unable to deploy PersistenceUnit [BBStatsPU] in invalid state [DeployFailed].
Internal Exception: javax.persistence.PersistenceException: 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 [Scores.is_home].
Descriptor: RelationalDescriptor(net.bbstats.entity.Score --> [DatabaseTable(Scores)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:634)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:222)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:330)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:350)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313)
at org.jboss.as.jpa.container.TransactionScopedEntityManager.createEntityManager(TransactionScopedEntityManager.java:187)
at org.jboss.as.jpa.container.TransactionScopedEntityManager.getOrCreateTransactionScopedEntityManager(TransactionScopedEntityManager.java:157)
at org.jboss.as.jpa.container.TransactionScopedEntityManager.getEntityManager(TransactionScopedEntityManager.java:87)
at org.jboss.as.jpa.container.AbstractEntityManager.createNamedQuery(AbstractEntityManager.java:101)
at net.bbstats.framework.service.Repository.findByNamedQuery(Repository.java:173)
at net.bbstats.framework.service.BaseEntityService.findByNamedQuery(BaseEntityService.java:467)
at net.bbstats.framework.service.BaseEntityService.findByNamedQuery(BaseEntityService.java:453)
at net.bbstats.framework.service.BaseEntityService.findByNamedQuery(BaseEntityService.java:429)
at net.bbstats.framework.service.BaseEntityService.findAllWithFetchGraph(BaseEntityService.java:385)
... 194 more
Caused by: Exception [EclipseLink-28013] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Unable to deploy PersistenceUnit [BBStatsPU] in invalid state [DeployFailed].
Internal Exception: javax.persistence.PersistenceException: 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 [Scores.is_home].
Descriptor: RelationalDescriptor(net.bbstats.entity.Score --> [DatabaseTable(Scores)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.exceptions.EntityManagerSetupException.cannotDeployWithoutPredeploy(EntityManagerSetupException.java:193)
... 208 more
Caused by: javax.persistence.PersistenceException: 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 [Scores.is_home].
Descriptor: RelationalDescriptor(net.bbstats.entity.Score --> [DatabaseTable(Scores)])
问题
我知道 JPA 实现可能假设每个 @Id
字段自动可写,但我想知道:JPA 是否在任何地方指定了这个?
我目前不明白为什么要做出这种可写性假设。
如果没有指定,这是一个错误吗?
在将 cascade = CascadeType.ALL
添加到您的 @OneToMany
映射后,我能够成功地保留具有多个分数的 Game
实体:
@OneToMany(mappedBy = "game", cascade = CascadeType.ALL) // added cascading
@MapKeyColumn(name = "is_home")
private Map<Boolean, Score> scores;
示例:
Game game = new Game();
game.setId(4);
// ...
Score score1 = new Score();
score1.setGame(game);
score1.setHome(true);
score1.setFinalScore(25);
Score score2 = new Score();
score2.setGame(game);
score2.setHome(false);
score2.setFinalScore(26);
game.getScores().put(score1.getHome(), score1);
game.getScores().put(score2.getHome(), score2);
entityManager.persist(game);
生成了以下 sql:
23:27:50,396 DEBUG SQL:127 -
/* insert com.my.entities.Game */
insert into TEST_SCHEMA.TST_GAMES (gm_id) values (?)
23:27:50,408 DEBUG SQL:127 -
/* insert com.my.entities.Score */
insert into TEST_SCHEMA.TST_SCORES (final_score, is_home, game_id)
values (?, ?, ?)
23:27:50,415 DEBUG SQL:127 -
/* insert com.my.entities.Score */
insert into TEST_SCHEMA.TST_SCORES (final_score, is_home, game_id)
values (?, ?, ?)
23:27:50,440 DEBUG SQL:127 -
update TEST_SCHEMA.TST_SCORES
set sc_is_home=?
where sc_is_home=? and sc_game_id=?
23:27:50,443 DEBUG SQL:127 -
update TEST_SCHEMA.TST_SCORES
set sc_is_home=?
where sc_is_home=? and sc_game_id=?
已使用 Hibernate 5.4 进行测试。10.Final。 (不添加上面提到的级联休眠也会生成异常)
您永远无法更改实体中的 ID 值,因此几乎暗示了 updatable=false;这样做是在创建一个新的身份,需要将其视为一个完全不同的实体。
错误消息是 pre-JPA 的延期。 EclipseLink 在其映射中将可插入与可更新联系在一起,以匹配其已有的 read-only 概念。 EclipseLink(以及 JPA 中实体的定义)要求,如果要插入一个实体,它有一个 ID 值,它可以在实体内控制 - 在这种情况下,您正试图让一些人设置 ID其他不符合实体含义的外部映射('game.scores' 关系)。这使它更像一个嵌入式对象。
我有一个游戏实体,它通过 Map
+ @MapKeyColumn
引用两个分数,其中一个实体用于主队,一个用于客队:
我决定使用 Boolean
列 is_home
来解决这个问题。我映射了 @MapKeyColumn
关系 而没有 insertable = false, updatable = false
,使关于 is_home
列的注释可写。
由于每列可能只有一个可写 field/annotation,我不得不将 insertable = false, updatable = false
添加到 Score
实体上的 @Id
映射,字段 home
,见下文。
游戏:
@Entity
@Table(name = "Games")
public class Game implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column
private Integer id;
@Basic(optional = false)
@Column(name = "scheduled_tipoff")
private LocalDateTime scheduledTipoff;
@OneToMany(mappedBy = "game")
@MapKeyColumn(name = "is_home") <- writable
private Map<Boolean, Score> scores;
...
}
得分:
@Entity
@Table(name = "Scores")
@IdClass(ScoreId.class)
public class Score implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "is_home", insertable = false, updatable = false) <- not writable
private Boolean home;
@Basic
@Column(name = "final_score")
private Integer finalScore;
@Id
@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "game_id")
private Game game;
...
}
分数:
public class ScoreId implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer game;
private Boolean home;
...
}
这导致使用 EclipseLink 时出现异常:
异常
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-28013] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Unable to deploy PersistenceUnit [BBStatsPU] in invalid state [DeployFailed].
Internal Exception: javax.persistence.PersistenceException: 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 [Scores.is_home].
Descriptor: RelationalDescriptor(net.bbstats.entity.Score --> [DatabaseTable(Scores)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:634)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:222)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:330)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:350)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313)
at org.jboss.as.jpa.container.TransactionScopedEntityManager.createEntityManager(TransactionScopedEntityManager.java:187)
at org.jboss.as.jpa.container.TransactionScopedEntityManager.getOrCreateTransactionScopedEntityManager(TransactionScopedEntityManager.java:157)
at org.jboss.as.jpa.container.TransactionScopedEntityManager.getEntityManager(TransactionScopedEntityManager.java:87)
at org.jboss.as.jpa.container.AbstractEntityManager.createNamedQuery(AbstractEntityManager.java:101)
at net.bbstats.framework.service.Repository.findByNamedQuery(Repository.java:173)
at net.bbstats.framework.service.BaseEntityService.findByNamedQuery(BaseEntityService.java:467)
at net.bbstats.framework.service.BaseEntityService.findByNamedQuery(BaseEntityService.java:453)
at net.bbstats.framework.service.BaseEntityService.findByNamedQuery(BaseEntityService.java:429)
at net.bbstats.framework.service.BaseEntityService.findAllWithFetchGraph(BaseEntityService.java:385)
... 194 more
Caused by: Exception [EclipseLink-28013] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Unable to deploy PersistenceUnit [BBStatsPU] in invalid state [DeployFailed].
Internal Exception: javax.persistence.PersistenceException: 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 [Scores.is_home].
Descriptor: RelationalDescriptor(net.bbstats.entity.Score --> [DatabaseTable(Scores)])
Runtime Exceptions:
---------------------------------------------------------
at org.eclipse.persistence.exceptions.EntityManagerSetupException.cannotDeployWithoutPredeploy(EntityManagerSetupException.java:193)
... 208 more
Caused by: javax.persistence.PersistenceException: 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 [Scores.is_home].
Descriptor: RelationalDescriptor(net.bbstats.entity.Score --> [DatabaseTable(Scores)])
问题
我知道 JPA 实现可能假设每个 @Id
字段自动可写,但我想知道:JPA 是否在任何地方指定了这个?
我目前不明白为什么要做出这种可写性假设。
如果没有指定,这是一个错误吗?
在将 cascade = CascadeType.ALL
添加到您的 @OneToMany
映射后,我能够成功地保留具有多个分数的 Game
实体:
@OneToMany(mappedBy = "game", cascade = CascadeType.ALL) // added cascading
@MapKeyColumn(name = "is_home")
private Map<Boolean, Score> scores;
示例:
Game game = new Game();
game.setId(4);
// ...
Score score1 = new Score();
score1.setGame(game);
score1.setHome(true);
score1.setFinalScore(25);
Score score2 = new Score();
score2.setGame(game);
score2.setHome(false);
score2.setFinalScore(26);
game.getScores().put(score1.getHome(), score1);
game.getScores().put(score2.getHome(), score2);
entityManager.persist(game);
生成了以下 sql:
23:27:50,396 DEBUG SQL:127 -
/* insert com.my.entities.Game */
insert into TEST_SCHEMA.TST_GAMES (gm_id) values (?)
23:27:50,408 DEBUG SQL:127 -
/* insert com.my.entities.Score */
insert into TEST_SCHEMA.TST_SCORES (final_score, is_home, game_id)
values (?, ?, ?)
23:27:50,415 DEBUG SQL:127 -
/* insert com.my.entities.Score */
insert into TEST_SCHEMA.TST_SCORES (final_score, is_home, game_id)
values (?, ?, ?)
23:27:50,440 DEBUG SQL:127 -
update TEST_SCHEMA.TST_SCORES
set sc_is_home=?
where sc_is_home=? and sc_game_id=?
23:27:50,443 DEBUG SQL:127 -
update TEST_SCHEMA.TST_SCORES
set sc_is_home=?
where sc_is_home=? and sc_game_id=?
已使用 Hibernate 5.4 进行测试。10.Final。 (不添加上面提到的级联休眠也会生成异常)
您永远无法更改实体中的 ID 值,因此几乎暗示了 updatable=false;这样做是在创建一个新的身份,需要将其视为一个完全不同的实体。
错误消息是 pre-JPA 的延期。 EclipseLink 在其映射中将可插入与可更新联系在一起,以匹配其已有的 read-only 概念。 EclipseLink(以及 JPA 中实体的定义)要求,如果要插入一个实体,它有一个 ID 值,它可以在实体内控制 - 在这种情况下,您正试图让一些人设置 ID其他不符合实体含义的外部映射('game.scores' 关系)。这使它更像一个嵌入式对象。