Hibernate映射:一个列映射到多个表

10
我有一个有关最佳实践的问题。
场景: 数据库中有多个实体,例如文档、博客文章和维基,可以由个人共享。而不是为每个实体创建一个共享表,创建了一个单一的共享表。问题在于,如何将共享表映射到不同的实体?
我有三个选项,请建议哪个选项最好,如果有更好的选项,请告知。 选项1: 创建名为“Shares”的表:
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将确定哪个关系是“活动”的。

选项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
请查看http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html。 - Stijn Geukens
谢谢,我会看看这个问题。但这真的是继承问题吗?或者说继承可以用来解决它。如果每个解析表都有附加的衍生信息,那么它们就可以符合继承的条件,但它们只包含与不同实体的关系。此外,大多数继承示例/文档并不尝试将单个列链接到不同实体。它们确实具有定义它们进一步的独立字段。 - M. Rather
再想一想,与不同实体的关系确实可以“进一步定义它们”。我会研究使用单表选项创建多个类,并看看它是如何工作的。 - M. Rather
运行得非常好。这个链接也有助于了解如何使用注释进行继承映射。http://codeidol.com/java/netbeans/Entity-Inheritance/Single-Table-per-Class-Hierarchy/ - M. Rather
2个回答

5

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方面,一个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());

}

0

这显然是多对多的关系。

映射这些类型的默认情况是使用一个单独的表来存储连接信息。类似于:

table shared_connections {
    number owner_id
    ,number shared_id
}

所有可共享的对象都应该扩展一些基本类,例如:AbstractSharedObject。(使用@MappedSuperclass注释并注意@Inheritance策略)。
在Individual类内部:
private Collection<AbstractSharedObject> shares;

将此集合映射为ManyToMany关系。

附注:为使其正常工作,您需要确保所有可共享对象的ID是唯一的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接