有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernate映射:一列到多个表

对于一个场景,我有一个“最佳实践”问题

情景: 一个数据库中的多个实体,例如文档、博客、Wiki,可以由个人共享。不再为每个实体创建共享表,而是创建单个共享表。问题是,如何将共享表映射到不同的实体

我有三种选择,请告知哪种选择最好,如果有更好的选择

选项1: 将表共享创建为:

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

在这里,entityId将是documentId、wikiId、postId等的FK,entityType将标识entityId的类型

在Hibernate建模中,当创建共享到实体的映射(如共享)时,这会出现问题。getDocument()或共享。getWiki()等

选项2: 创建仅保存共享信息的表共享,然后创建将共享绑定到实体的解析表

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将标识哪个关系处于“活动”状态)

选项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.拉蒂


共 (2) 个答案

  1. # 1 楼答案

    这显然是一种多对多的关系

    映射这些类型内容的默认方案是使用一个单独的表来获取连接信息。 比如:

    table shared_connections {
        number owner_id
        ,number shared_id
    }
    

    所有可共享的对象都应该扩展一些基本类,例如:AbstractSharedObject。(使用@MappedSuperclass注释并关注@Inheritation strategy)

    在个人课堂上:

    private Collection<AbstractSharedObject> shares;
    

    将此集合映射为ManyToMany关系

    另外,要想实现这一点,你需要保证所有可共享对象的ID都是唯一的

  2. # 2 楼答案

    正如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方面, 一个共享抽象类为

    @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());
    
    }