2011-12-01 15 views
7

Mam pytanie "najlepsza praktyka" dla scenariusza.Mapowanie hibernacji: jedna kolumna na wiele tabel

Scenariusz: Wiele podmiotów w bazie danych, na przykład Dokument, BlogPost, Wiki mogą być udostępniane przez użytkowników indywidualnych. Zamiast tworzenia tabeli udziałów dla każdej jednostki, tworzona jest pojedyncza tabela Udziałów. Problem polega na tym, jak zmapować tabelę udziałów z różnymi jednostkami?

Mam trzy opcje, proszę doradzić, która opcja jest najlepsza, a jeśli jest lepsza opcja.

Opcja 1: Tworzenie Akcji tabeli jako:

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

Tutaj identyfikator podmiotu będzie FK do documentId, wikiId, postID itp itd i entityType będzie tożsamość jaki rodzaj identyfikator podmiotu jest.

ten ma problemy w modelowaniu hibernacji, podczas tworzenia Wyślij do mapowania jednostki, takie jak share.getDocument() lub() itp share.getWiki

Opcja 2: Tworzenie Akcji stół, który posiada jedynie udziały informacje, a następnie utworzyć tabele rozdzielczości, które wiążą udział z jednostką.

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. 

Więc hibernacji mądry, Udział może mieć jeden do jednego dla każdego z rodzajów akcji (jak share.getDocument(), share.getPost() i shareType będzie zidentyfikować związek jest „aktywny”)

Wariant 3 Podobnie jak w wariancie 1, ale zamiast tworzyć poszczególne kolumny podmiotu id

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

Tutaj, każda kolumna może być odwzorowany do danego podmiotu, ale są one pustych. Metoda sharedType może określić, która relacja jest "aktywna".

Pytanie brzmi więc, która praktyka jest najlepsza, zarówno w zakresie mapowania, jak i mapowania hibernacji (i ewentualnych zapytań, pod względem wydajności).

Dzięki M. Raczej

+1

Wystarczy popatrzeć na http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html –

+0

Dzięki, przyjrzę się temu. Ale czy to naprawdę kwestia dziedziczenia? Lub dziedziczenie może być użyte do rozwiązania tego problemu. Jeśli każda z tabel rozdzielczości ma dodatkowe informacje pochodne, mogą kwalifikować się do dziedziczenia, ale po prostu zawierają relację z różnymi podmiotami. Ponadto większość przykładów/dokumentacji dziedziczenia nie próbuje utworzyć pojedynczego łącza do kolumn z różnymi obiektami. Mają naprawdę niezależne pola, które je definiują. –

+0

W drugiej chwili relacje z różnymi podmiotami "definiują je dalej". Przyjrzę się wielu klasom z opcją pojedynczej tabeli i zobaczę, jak to działa. –

Odpowiedz

4

Jak sugeruje TheStijn, po spojrzeniu na różne sposoby do relacji ustawień dziedziczenia, poszedłem z „jednolitej tabeli na klasy hierarchii” podejścia, a skończyło się na stole jak:

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

Na hibernacji/Java boczny, jedną akcję klasa abstrakcyjna jak ...

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

} 

a dwa normalne zajęcia ..

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

} 

Co do użycia, należy wykonać konkretne zajęcia jedynie jako:

@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

Jest to oczywiście wiele-do-wielu.

Domyślnym scenariuszem odwzorowywania tego typu rzeczy jest użycie oddzielnej tabeli dla informacji o połączeniu. Coś jak:

table shared_connections { 
    number owner_id 
    ,number shared_id 
} 

Wszystkie obiekty, które są współdzielone powinny rozszerzyć podstawowe klasy Ex: AbstractSharedObject. (użyj adnotacji @MappedSuperclass i dbaj o strategię @ Dziedzictwo).

i wewnątrz klasy indywidualną:

private Collection<AbstractSharedObject> shares; 

mapie tej kolekcji jak ManyToMany relacji.

P.S. Aby to działało, musisz zagwarantować, że identyfikatory wszystkich udostępnianych obiektów będą unikalne.

Powiązane problemy