2011-12-01 18 views
7

Tengo una pregunta de "mejores prácticas" para un escenario.Asignación de Hibernación: de una columna a varias tablas

Escenario: Las entidades múltiples en un DB, por ejemplo, Document, BlogPost, Wiki pueden ser compartidas por individuos. En lugar de crear una tabla de acciones para cada entidad, se crea una sola tabla de Acciones. El problema es cómo asignar la tabla de acciones con diferentes entidades.

Tengo tres opciones, indique cuál es la mejor opción y si hay una mejor opción.

Opción 1: crear recursos compartidos de mesa como:

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

Aquí, entityId será una FK a documentId, wikiId, postID etc., etc., y se entityType identidad de qué tipo es el entityId.

Esto tiene problemas en el modelado de hibernación, al crear Compartir a la cartografía de entidad, como share.getDocument() o share.getWiki(), etc.

Opción 2: crear recursos compartidos de mesa que sólo se ejerce en la cuota información, y luego crear tablas de resolución que relacionen la acción con la entidad.

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. 

Así, hibernación sabia, Compartir puede tener de uno a uno para cada uno de los tipos de acciones (como share.getDocument(), share.getPost(), y shareType identificará el que la relación es 'activa')

opción 3 al igual que en la opción 1, pero crear columnas individuales en lugar de entidad Identificación

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

Aquí, cada columna podría ser asignada a la respectiva entidad, pero son anulables. sharedType puede identificar qué relación es 'activa'.

Entonces, la pregunta es, qué práctica es la mejor, tanto en la base de datos como en el mapeo de hibernación (y eventual consulta, en cuanto al rendimiento).

Gracias M. Más bien

+1

Tenga una mirada en http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html –

+0

Gracias, veremos esto. Pero, ¿es esto realmente un problema de herencia? O la herencia se puede usar para resolverlo. Si cada una de las tablas de resolución tuviera información adicional derivada, entonces podrían calificar para la herencia, pero solo contienen una relación con diferentes entidades. Además, la mayoría de los ejemplos/documentación de herencia no intentan hacer un solo enlace de columna a diferentes entidades. Realmente tienen campos independientes que los definen más. –

+0

En un segundo pensamiento, las relaciones con diferentes entidades 'las definen más'. Examinaré varias clases con la opción de tabla única y veré cómo funciona. –

Respuesta

4

Como sugiere TheStijn, después de mirar en diferentes formas de relaciones de herencia configuración, fui con 'tabla individual por jerarquía de clases' enfoque, y terminó con la mesa como:

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 ...) 

En Hibernate/Java lado, Compartir Una clase abstracta como ...

@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;   
    ... 

} 

Y dos clases normales ..

@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; 
    .... 

} 

En cuanto a su uso, utilizar las clases concretas sólo como:

@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

Esto es claramente una relación de muchos a muchos.

Escenario predeterminado para mapear ese tipo de cosas es utilizar una tabla separada para la información de conexión. Algo así como:

table shared_connections { 
    number owner_id 
    ,number shared_id 
} 

Todos los objetos que son compartibles debe extenderse algunos básicos ex clase: AbstractSharedObject. (utilice la anotación @MappedSuperclass y cuídese de la estrategia @ Herencia).

y en el interior de clase individual:

private Collection<AbstractSharedObject> shares; 

mapa esta colección como ManyToMany relación.

P.S. Para que esto funcione, deberá garantizar que los identificadores de todos los objetos compartibles sean únicos.

Cuestiones relacionadas