首页 > 解决方案 > 没有 SecondaryTable 的两个表的 JPA 一个实体

问题描述

我描述了一些由文件夹和文档组成的 ECM 域模型。简单来说,文件夹可以包含文档和其他文件夹(子文件夹)。文件夹和文档都有属性。属性可以是不同的类型。

在 OOP 中,该模型由下图描述

我需要将此结构映射到数据库表。

当我尝试将Attr实体映射到数据库中的表时,我的问题就出现了。 与实体Attr具有多对一的关系。这意味着表必须有两个外键:和分别。DocumentFolderATTRDOCUMENT_FKFOLDER_FK

因此ER图看起来像这样

以及对应的JPA映射:


package ru.max.db.folders.domain

import javax.persistence.*

@Entity
@Table(name = "ATTR_TYPE")
class AttrType(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,
    val name: String
)

@Entity
@Table(name = "ATTR")
class Attr(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,
    @ManyToOne
    @JoinColumn(name = "TYPE")
    val type: AttrType,
    val value: String
)

@Entity
@Table(name = "DOCUMENT")
class Document(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,
    val type: String,
    @ManyToOne
    @JoinColumn(name = "PARENT_FOLDER")
    val parentFolder: Folder,
    @OneToMany
    @JoinColumn(name = "DOCUMENT_ID")
    val attrs: MutableList<Attr>?
)

@Entity
@Table(name = "FOLDER")
class Folder(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,
    val clazz: String,
    @OneToMany
    @JoinColumn(name = "FOLDER_ID")
    val attrs: MutableList<Attr>?,
    @OneToMany
    @JoinColumn(name = "PARENT_FOLDER")
    val subFolders: MutableList<Folder>?,
    @OneToMany
    @JoinColumn(name = "PARENT_FOLDER")
    val documents: MutableList<Document>?
)

这个解决方案的问题是ATTR.FOLDER_IDATTR.DOCUMENT_ID键列必须可以为空,并且一些行将指向文件夹的属性,而另一行将指向文档的属性。这对我来说看起来不太好。

我想要的是ATTR分成两个不同的表FOLDER_ATTRDOCUMENT_ATTR. 是对应的ER图:

FOLDER_ATTR具有与 相同的结构DOCUMENT_ATTR。因此它可以用一个 JPA 实体来表示。但是我怎么能用 JPA 注释(或者,也许用 .xml)来描述这个映射呢?

当然我不能在实体上使用两个@Table注释:Attr


@Entity
@Table(name = "DOCUMENT_ATTR")
@Table(name = "FOLDER_ATTR")
class Attr(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,
    @ManyToOne
    @JoinColumn(name = "TYPE")
    val type: AttrType,
    val value: String
)

@Entity
@Table(name = "DOCUMENT")
class Document(
    ...
    @OneToMany
    @JoinColumn(name = "OBJECT_ID")
    val attrs: MutableList<Attr>?
)

@Entity
@Table(name = "FOLDER")
class Folder(
    ...
    @OneToMany
    @JoinColumn(name = "OBJECT_ID")
    val attrs: MutableList<Attr>?,
    ...
)

有可能以某种方式在这里实现我想要的吗?我不想让两个不同的类代表相同的结构只是为了适应数据库模型。

标签: javahibernatekotlinjpa

解决方案


您可以保持对象模型不变,而不是在 ATTR 表上使用两个外键,如果这对您更有意义,您可以使用两个连接表(DOCUMENT_ATTR,FOLDER_ATTR)

@Entity
@Table(name = "DOCUMENT")
class Document(
    ...
    @OneToMany
    @JoinColumn(
       name = "DOCUMENT_ATTR",
       joinColumns = @JoinColumn( name="document_id"),
       inverseJoinColumns = @JoinColumn( name="attr_id")
    )
    val attrs: MutableList<Attr>?
)

@Entity
@Table(name = "FOLDER")
class Folder(
    ...
    @OneToMany
    @JoinTable(
       name = "FOLDER_ATTR",
       joinColumns = @JoinColumn( name="folder_id"),
       inverseJoinColumns = @JoinColumn( name="attr_id")
    )
    val attrs: MutableList<Attr>?,
    ...
)

推荐阅读