Hibernate映射:一列到多个表

时间:2011-12-01 16:26:59

标签: 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等的FK,entityType将识别entityId的类型。

在创建Share to entity映射时,Hibernate建模存在问题,例如share.getDocument()或share.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. Rather

2 个答案:

答案 0 :(得分:4)

正如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());

}

答案 1 :(得分:0)

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

映射这些类型的事物的默认方案是使用单独的表来获取连接信息。 类似的东西:

table shared_connections {
    number owner_id
    ,number shared_id
}

所有可共享的对象都应扩展一些基本类ex:AbstractSharedObject。 (使用@MappedSuperclass注释并关注@Inheritance策略。)

和个人课程内部:

private Collection<AbstractSharedObject> shares;

将此集合映射为ManyToMany关系。

P.S。为此,您需要保证所有可共享对象的ID都是唯一的。