我有一个非常不寻常的JPA / Hibernate案例。我把我的例子推到了GitHub。
我有一个名为PlayerStatistics
的类,其中我使用由matchday
和player
字段组成的复合主键。同时,还有一个名为Match
的实体的引用,其主键也是复合键,由matchday
和homeTeam
组成。
现在,matchday
字段在功能上对于它们都是相同的字段。
为了避免在DDL中重复此字段(我的模式是从对象模型生成的),我使用了@ForeignKeys
注释。
@Id
@ManyToOne(optional = false)
@PrimaryKeyJoinColumn
private Player player;
@Id
@ManyToOne(optional = false)
@PrimaryKeyJoinColumn
private Matchday matchday;
@ManyToOne(optional = false)
@JoinColumns({ @JoinColumn(name = "matchday_matchdaynumber", referencedColumnName = "matchday_matchdaynumber"),
@JoinColumn(name = "hometeam_name", referencedColumnName = "hometeam_name") })
private Match match;
它就像一个魅力,它的DDL就是这样创建的(没有比赛日列重复)。
Hibernate:
create table PlayerStatistics (
enteredTheFieldAtInSeconds integer not null check (enteredTheFieldAtInSeconds>=0),
leftTheFieldAtInSeconds integer not null check (leftTheFieldAtInSeconds>=0),
playedFromTheFirstWhistleblow boolean not null,
matchday_matchdayNumber integer not null,
player_id bigint not null,
hometeam_name varchar(255) not null,
primary key (matchday_matchdayNumber, player_id)
)
然而,当谈到DML,特别是INSERT查询时,Hibernate似乎不再那么聪明了。列matchday_matchdayNumber
指定了两次。
Hibernate:
insert
into
PlayerStatistics
(enteredTheFieldAtInSeconds, leftTheFieldAtInSeconds, hometeam_name, matchday_matchdaynumber, playedFromTheFirstWhistleblow, matchday_matchdayNumber, player_id)
values
(?, ?, ?, ?, ?, ?, ?)
这当然有一个例外(我使用HSQLDB进行单元测试)。
2016-11-22 09:41:10.056 WARN 5892 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: -5579, SQLState: 42579
2016-11-22 09:41:10.056 ERROR 5892 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : duplicate update of column: MATCHDAY_MATCHDAYNUMBER
我对PostgreSQL的集成测试也一样,所以它似乎不依赖于RDBMS。问题似乎在于Hibernate。
2016-11-22 10:08:42.316 WARN 6696 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42701
2016-11-22 10:08:42.317 ERROR 6696 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: column "matchday_matchdaynumber" specified more than once
我的问题是。有什么办法可以避免吗?我如何"告诉" Hibernate matchday
中的PlayerStatistics
和matchday
中的Match
实际上属于同一个属性?
遗憾的是,对我来说,使用合成密钥是不可能的。
可以通过在班级com.example.DemoApplicationTests
中运行单元测试来重现错误。