【问题标题】:Hibernate mapping: one column to multiple tablesHibernate 映射:一列到多个表
【发布时间】:2012-01-10 19:08:56
【问题描述】:

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

场景: 数据库中的多个实体,例如 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 的类型。

这在 Hibernate 建模中存在问题,在创建 Share 到实体映射时,例如 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.

因此,在休眠方面,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 可以识别哪个关系是“活跃的”。

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

谢谢 M.宁可

【问题讨论】:

  • 谢谢,会调查的。但这真的是继承问题吗?或者可以使用继承来解决它。如果每个解析表都有额外的派生信息,那么它们就有资格继承,但它们只包含与不同实体的关系。此外,大多数继承示例/文档不会尝试将单个列链接到不同的实体。它们确实具有独立的字段,可以进一步定义它们。
  • 再想一想,与不同实体的关系确实“进一步定义了它们”。我将使用单表选项研究多个类,看看它是如何工作的。
  • 就像一个魅力。这个链接对于如何使用继承映射的注解也很有帮助。codeidol.com/java/netbeans/Entity-Inheritance/…

标签: java hibernate mapping


【解决方案1】:

根据 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());

}

【讨论】:

    【解决方案2】:

    这显然是多对多的关系。

    映射这些类型的事物的默认方案是使用单独的表来存储连接信息。 比如:

    table shared_connections {
        number owner_id
        ,number shared_id
    }
    

    所有可共享的对象都应该扩展一些基本类,例如:AbstractSharedObject。 (使用@MappedSuperclass 注解,关心@Inheritance 策略)。

    在个人类中:

    private Collection<AbstractSharedObject> shares;
    

    将此集合映射为ManyToMany 关系。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-12
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 2014-01-15
      • 2013-08-20
      • 2010-12-12
      相关资源
      最近更新 更多