java - hibernate 映射 : one column to multiple tables

标签 java hibernate mapping

我有一个场景的“最佳实践”问题。

场景: 数据库中的多个实体,例如 Document、BlogPost、Wiki 可以由个人共享。不是为每个实体创建一个共享表,而是创建一个共享表。问题是,如何将共享表映射到不同的实体?

我有三个选项,请告知哪个选项最好,如果有更好的选项。

选项 1: 创建表共享为:

SHARES  
id (unique)
entityId (non DB enforced FK to DOCUMENTS, WIKIS, POSTS etc.)
entityType
sharedBy
sharedWith
sharedDate

在这里,entityId 将是 documentId、wikiId、postId 等的外键,而 entityType 将标识 entityId 的类型。

这在 Hibernate 建模中存在问题,当创建共享到实体映射时,例如 share.getDocument() 或 share.getWiki() 等。

选项 2: 创建仅包含共享信息的表 Shares,然后创建将共享与实体相关联的解析表。

SHARES
id(PK)
sharedBy
sharedWith
sharedDate
shareType (helper field for searches)

SHARES_DOCUMENTS
share_id (unique ID and FK, one to one with SHARES)
document_id (FK to DOCUMENTS)

SHARES_POST
share_id (unique ID and FK, one to one with SHARES)
post_id (FK to POSTS)

more share tables here.

因此,在 hibernate 模式下,Share 可以与每种共享类型一对一(例如 share.getDocument()、share.getPost() 和 shareType 将确定哪个关系是“Activity 的”)

选项 3 与选项 1 类似,但创建单独的列而不是实体 ID

SHARES
id (unique ID)
documentId (FK to DOCUMENTS, nullable)
postId (FK to POSTS, nullable)
wikiId (FK to WIKIS, nullable)
sharedBy
sharedWith
sharedDate
sharedType

在这里,每一列都可以映射到各自的实体,但它们可以为空。 sharedType 可以识别哪个关系是“活跃的”。

所以,问题是,哪种做法最好,无论是数据库方面还是 hibernate 映射(以及最终查询,性能方面)。

谢谢 M.宁愿

最佳答案

根据 TheStijn 的建议,在研究了设置继承关系的不同方法后,我采用了“每个类层次结构一个表”的方法,并最终得到如下表:

SHARES
---------
id PK
shared_by FK to User
shared_with FK to User
shared_Date
document_id nullable FK to Document
post_id nullable FK to Posts
... more ids here to link to more entities
type_discriminator (values, DOCUMENT, POST ... )

在 Hibernate/Java 方面, One Share 抽象类为...

@Entity
@Table(name="SHARES")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE_DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING)
public abstract class Share {
    @Id
    @Column( name="ID", nullable=false )
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;

    @ManyToOne
    @JoinColumn( name="SHARED_BY", nullable=false )
    private User sharedBy;

    @ManyToOne
    @JoinColumn( name="SHARED_WITH", nullable=false )
    private User sharedWith;

    @Column(name="SHARED_DATE", columnDefinition="TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP", nullable=false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date sharedDate;        
    ...

}

还有两个普通类..

@Entity
@DiscriminatorValue("DOCUMENT")
public class SharedDocument extends Share { 
    @ManyToOne
    @JoinColumn( name="DOCUMENT_ID", nullable=true )
    private Document document;
    ....

}

@Entity
@DiscriminatorValue("POST")
public class SharedPost extends Share {
    @ManyToOne
    @JoinColumn( name="POST_ID", nullable=true )
    private Post post;
    ....

}

至于用法,仅将具体类用作:

@Test
public void saveNewDocumentShare(){
    SharedDocument sharedDocument = new SharedDocument();
    sharedDocument.setDocument(document1);
    sharedDocument.setSharedBy(teacher1);
    sharedDocument.setSharedWith(teacher2);
    sharedDocument.setSharedDate(new Date());

    sharedDocument.setCreatedBy("1");
    sharedDocument.setCreatedDate(new Date());
    sharedDocument.setModifiedBy("1");
    sharedDocument.setModifiedDate(new Date());


    SharedDocument savedSharedDocument = dao.saveSharedDocument(sharedDocument);

    assertNotNull(savedSharedDocument);
    assertThat(savedSharedDocument.getId(),notNullValue());
}

@Test
public void saveNewPostShare(){
    SharedPost sharedWikiPage = new SharedWikiPage();
    sharedPost.setPost(post1);
    sharedPost.setSharedBy(teacher1);
    sharedPost.setSharedWith(teacher2);
    sharedPost.setSharedDate(new Date());

    sharedPost.setCreatedBy("1");
    sharedPost.setCreatedDate(new Date());
    sharedPost.setModifiedBy("1");
    sharedPost.setModifiedDate(new Date());


    SharedPost savedSharedPost = dao.saveSharedPost(sharedPost);

    assertNotNull(savedSharedPost);
    assertThat(savedSharedPost.getId(),notNullValue());

}

关于java - hibernate 映射 : one column to multiple tables,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8344731/

相关文章:

java - 永久使用 Socket 来处理 ClientSession 或为每个请求创建一个新的 ClientSession

java - 如何主动将 JLabels 从 ArrayList 设置到 JPanel?

java - 需要从绑定(bind)文件在 package-info.java 中生成 JAXB 注释

java - JPA(Hibernate 支持)Maker-Checker 多级继承

java - MyBatis:如何存储查询中的多个值?

java - 根据 android studio 编译器,数据库表不存在

hibernate - Grails 何时使用merge() 而不是save()?

java - JPA - 设置双向关系 -> 从 OneToMany-Collection 加载所有元素的开销很大吗?

templates - 如何在 ElasticSearch 中正确定义 HashMap

mysql - 异常(exception)是 org.hibernate.hql.internal.ast.QuerySyntaxException : books is not mapped [FROM books. ..