来自具有非唯一 ID 的表的 JPA 实体
Posted
技术标签:
【中文标题】来自具有非唯一 ID 的表的 JPA 实体【英文标题】:JPA entity from a table with non-unique id 【发布时间】:2016-03-30 07:34:06 【问题描述】:我想要一个实体
class InkFormula
int id;
Map<Ink, Integer> inkPercents;
...
来自具有这种结构的单个表:
┌─────┬────────┬─────────┐
│ id │ ink_id │ percent │
├─────┼────────┼─────────┤
│ 1 │ 1 │ 50 │
├─────┼────────┼─────────┤
│ 1 │ 2 │ 25 │
├─────┼────────┼─────────┤
│ 1 │ 3 │ 0 │
├─────┼────────┼─────────┤
│ 2 │ 1 │ 100 │
├─────┼────────┼─────────┤
│ 2 │ 2 │ 80 │
└─────┴────────┴─────────┘
必须使用非唯一的id
来聚集来自ink_id
和percent
的Map<>
。
我需要一个实体和一个表的原因是要求具有唯一约束id
,ink_id
,以便每个公式不能包含重复的墨水。
JPA 和 Hibernate 可以做到吗?
【问题讨论】:
什么映射到“百分比”? Map我将创建一个复合主键 InkFormulaId
,其中包含两个字段:id
和 ink_id
,类似于
@Embeddable
public class InkFormulaId implements Serializable
private Integer id;
private Integer inkId;
// ...
@Entity
public class InkFormula
@EmbeddedId
private InkFormulaId inkFormulaId;
@ManyToOne
@MapsId(value = "inkId")
private Ink ink;
private Integer percents;
// ...
所以每个InkFormula
代表上表中的一行,具有唯一的主键(id
、inkId
)及其percents
。
要获得您上面提到的映射,您必须将 SELECT
all InkFormula
用于单个 id
,然后在您的 Java 代码中按 inkId
对它们进行分组。
【讨论】:
我想要的是来自所有行的InkFormula
实体,具有相同的id
,而不是每一行。这是一个挑战。
这是不可能的,因为单行有多个值会破坏“ACID”(en.wikipedia.org/wiki/ACID) 中的“A”,并且每个 JPA 实体代表单行。
好的,我们可以把InkFormula
的id
放到一个单独的ink_formula
表中。然后让这个表被称为ink_formula_percent
。但问题仍然存在:如何将ink_formula
和ink_formula_percent
加入到一个实体中。
为什么是另一个表 - 你试过我上面的例子吗?它导致一个表,您只需手动将InkFormula
对象分组,首先按id
,然后按inkId
。
谢谢,Smutje,我试过了——效果很好。但是我懒得手动分组Map<>
。我想让它由 Hibernate 和数据库完成。或者,如果没有太多工作,我可能不知道如何做到这一点?请参阅下面的替代解决方案。【参考方案2】:
另一种解决方案是使用@ElementCollection
注释并将数据分成两个表:
ink_formula ink_formula_ink_percent
┌───┐ ┌──────────────┬──────┬───────┐
│id │ │ink_formula_id│ink_id│percent│
├───┤ ├──────────────┼──────┼───────┤
│ 1 │ │ 1 │ 1 │ 20 │
├───┤ ├──────────────┼──────┼───────┤
│ 2 │ │ 1 │ 2 │ 55 │
├───┤ ├──────────────┼──────┼───────┤
. . . . . . . . . . . . . . . . . . .
实体类将如下所示
@Entity
public class InkFormula
@Id
@GeneratedValue
int id;
@ElementCollection
@CollectionTable(
name="ink_formula_ink_percent",
joinColumns=@JoinColumn(name="ink_formula_id")
)
@MapKeyJoinColumn(name="ink_id")
@Column(name = "percent")
private Map<Ink, Integer> inkPercents = new TreeMap<>();
//...
此设置满足独特的 InkFormula-Ink
要求,但我们需要为 InkFormula
提供单独的表。
下一个问题是如何确保每个InkFormula
的唯一性,因为具有不同id
s 的两个InkFormulas
可以在它们的inkPercents
映射中保存相同的值。
【讨论】:
以上是关于来自具有非唯一 ID 的表的 JPA 实体的主要内容,如果未能解决你的问题,请参考以下文章
可以将@Id添加到映射到Spring boot Jpa中没有主键列的表的实体吗?