【发布时间】:2020-06-15 03:28:38
【问题描述】:
class Game(
@MappedCollection(idColumn = "game") <---- unnecessary
var rules: List<Rule> = emptyList(),
){
@Id
var id: Long? = null
}
data class Rule(
@MappedCollection(idColumn = "rule", keyColumn = "rule_key")<---- unnecessary
val ruleValues: List<RuleValue>
)
data class RuleValue(val value: String)
架构是
create table game
(
id serial primary key
);
create table rule
(
id serial primary key,
game long references game (id),
game_key integer
);
create table rule_value
(
id serial primary key,
game long references game (id),
game_key integer,
rule long references rule (id),
rule_key integer,
value varchar(256)
);
简而言之,我有一个 Game 作为根聚合。 game 有一个Rules 的列表(顺序很重要),rule 有一个rule values 的列表(顺序很重要)。 rule value 现在只是一个字符串,但将来可能会扩展。
我有两个问题:
1) 找不到所需的标识符属性:当我尝试保存游戏时,我收到Caused by: java.lang.IllegalStateException: Required identifier property not found for class com...RuleValue!
异常消息。
2) java.sql.SQLSyntaxErrorException:为什么我需要rule_value 表中的game 和game_key 列?如果我不放它们,我会得到Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'game_key' in 'field list'
我使用 Spring Boot 版本 2.2.5.RELEASE 和 org.springframework.boot:spring-boot-starter-data-jdbc 对应于 spring-data-jdbc 版本 1.1.5.RELEASE
SOLUTION-1:在类中添加 ID 字段
正如@chrylis-onstrike- 建议的那样,我在所有数据类中添加了@Id 字段
class Game(
@MappedCollection(idColumn = "game")
var rules: List<Rule> = emptyList(),
){
@Id
var id: Long? = null
}
data class Rule(
@MappedCollection(idColumn = "rule", keyColumn = "rule_key")
val ruleValues: List<RuleValue>
) {
@Id
var id: Long? = null <---- this is new
}
data class RuleValue(val value: String) {
@Id
var id: Long? = null <---- this is new
}
并且架构更改为
create table game
(
id serial primary key
);
create table rule
(
id serial primary key,
game long references game (id),
game_key integer
);
create table rule_value
(
id serial primary key,
# game long references game (id), <---- removed this
# game_key integer, <---- removed this
rule long references rule (id),
rule_key integer,
value varchar(256)
);
SOLUTION-2:在脚本中添加复合主键
class Game(
@MappedCollection(idColumn = "game")
var rules: List<Rule> = emptyList(),
){
@Id
var id: Long? = null
}
data class Rule(
@MappedCollection(idColumn = "rule", keyColumn = "rule_key")
val ruleValues: List<RuleValue>
)
data class RuleValue(val value: String)
并且架构更改为
create table game
(
id serial primary key
);
create table rule
(
# id serial primary key, <---- removed
game integer,
game_key integer,
primary key (game, game_key) <---- added
);
create table rule_value
(
# id serial primary key, <---- removed
game integer, <---- added
game_key integer, <---- added
rule_key integer,
value varchar(2048),
primary key (game, game_key, rule_key) <---- added
);
结论
您需要确定您的对象是value objects 还是实体。值对象在类中可能不应该有 id 字段,因为它的身份是由它携带的值定义的。但是,您需要识别数据库表中的一行并将其与其所有者相关联,因此如果要将它们持久保存在不同的表中,则需要在值对象中创建复合主键。
【问题讨论】:
-
嗯?您的
RuleValue类似乎只有一个属性String value。 -
@chrylis-onstrike-
A rule value is just a string for now but may extend in the future.问题不在于它只是一个字符串值。 -
这正是问题:你的类没有主键,这正是 Spring Data 告诉你的。
-
@chrylis-onstrike- 在所有教程中这样的数据类没有
Id但聚合根为什么我需要添加和Id到数据类? -
您的问题现在很长,包含历史、解决方案和另一个问题。看起来更像是一场讨论。
标签: java mysql kotlin spring-data spring-data-jdbc