2011-12-23 18 views
12

Mam pytanie podobne do @ManyToMany without join table (legacy database) z dodatkowym problemem.Mapowanie bazy danych tylko do odczytu z relacją wiele do wielu bez tabeli łączenia

że dwie tabele A i B

  • A z kluczem wielokolumnowy podstawowej (ID i ID2)
  • B kluczem wielokolumnowy podstawowej (ID i ID3)

Wiersz w A może odwoływać się do kilku wierszy w B (B.ID = A.ID) i wiersz B można odwoływać się przez kilka wierszy w A.

EDIT: baza danych jest starą bazą danych tylko do odczytu, której nie można zmienić. Nie muszę mapować relacji z JPA (mógłbym to zrobić w logice programu z dodatkowymi wyborami), ale byłoby miło.

Jest to w zasadzie relacja wiele do wielu bez tabeli sprzężenia. Ponieważ, jak w przypadku połączonego pytania, po prostu muszę czytać tabele, próbowałem z dwoma relacjami jeden do wielu w obu klasach.

Dodatkowym problemem, który mam, jest to, że zarówno ID s używane do łączenia nie są kluczem podstawowym.

Mam następujących klas:

@Entity 
@Table(name = "A") 
@IdClass(PrimaryKeysA.class) 
public class A { 

    @Id 
    @Column(name = "ID", insertable = false, updatable = false, columnDefinition = "char") 
    private String id; 

    @Id 
    @Column(name = "ID2", insertable = false, updatable = false) 
    private int id2; 

    @OneToMany(cascade = CascadeType.ALL) 
    @JoinColumn(name = "ID", columnDefinition = "char", referencedColumnName = "ID") 
    private Set<B> setOfBs; 

} 

@Entity 
@Table(name = "B") 
@IdClass(PrimaryKeysB.class) 
public class B { 

    @Id 
    @Column(name = "ID", insertable = false, updatable = false, columnDefinition = "char") 
    private String id; 

    @Id 
    @Column(name = "ID3", insertable = false, updatable = false) 
    private int id3; 

    @OneToMany(cascade = CascadeType.ALL) 
    @JoinColumn(name = "ID", columnDefinition = "char", referencedColumnName = "ID") 
    private Set<A> setOfAs; 

} 

Hibernacja generuje następujący błąd:

Exception while preparing the app : referencedColumnNames(ID) of package.B referencing package.A not mapped to a single property 

naprawdę nie dostaję komunikat: B.id odwołuje się do pojedynczego obiektu A (A.id) .

Edycja: a o:

public class PrimaryKeysA implements Serializable { 

private static final long serialVersionUID = 1L; 

private int id1; 
private int id2; 

    // getters/setters/equals/hashcode 

} 

PrimaryKeysB jest podobna id3 zamiast ID2. Obie klasy: A i B są uproszczonymi (anonimowymi) przykładami.

+1

Naprawdę nie widzę, jak można mieć wiele-do-wielu z tymi tabelami. O identyfikatorze B.ID B.ID i B.ID jest kluczem podstawowym B. Tak więc dany A może odnosić się tylko do jednego B. Po prostu masz powiązanie ManyToOne od A do B. –

+0

Ooops przepraszam, że mam to samo na A jak w B. Będę edytować pytanie (próbowałem wygenerować uproszczony przykład idący zbyt daleko) – Matteo

+0

To nie jest wiele powiązań między dwiema tabelami ... Dlaczego używasz dwóch identyfikatorów na każdej tabeli? Czy masz możliwość zmiany tego schematu na bardziej standardową formę lub czy jest to starsza baza danych? Jeśli nie jest to starsza baza danych, dlaczego nie używasz tabeli łączenia, jeśli chcesz powiązać wiele do wielu? –

Odpowiedz

4

Można utworzyć widok, który będzie działał jako dołączyć tabelę:

CREATE VIEW AJOINB AS 
SELECT A.ID as AID, A.ID2 as AID2, B.ID as BID, B.ID3 as BID3 
FROM A JOIN B ON A.ID = B.ID 

A potem na mapę w WZP jako ManyToMany z AJOINB jak dołączyć tabelę.

Jeśli identyfikatory A.ID2 i B.ID3 były unikatowe same, nie trzeba nawet mapować A.ID i B.ID w komponentach JPA.

+0

Ponieważ DB jest tylko do odczytu, musiałbym utworzyć nowy DB z kopią wszystkich tabel plus dodatkowy widok (ponieważ I nie sądzę, żebym mógł zdefiniować dwie jednostki na DB i tabeli sprzężenia na innej). Będąc zmuszonym do korzystania z dodatkowej bazy danych, starałbym się poprawić dane w lepszy sposób. Ale może być warta ... – Matteo

+0

Zależy od twojego DB. W Oracle i SQL Server można używać aliasów tabel. A tworzenie widoków na schematach jest możliwe nawet w MySQL. – greyfairer

+0

Tak tworzenie widoku w innym schemacie nie stanowi problemu. Obawiam się (nie sprawdziłem), że definiowanie podmiotu w jednym schemacie przy użyciu tabeli dołączenia w innym nie będzie działać. Ale będę musiał pracować z łączem DB, ponieważ DB (nie tylko schemat) jest tylko do odczytu: Nie mam innego dostępu. – Matteo

2

Czy możesz udostępnić próbki rekordów z tabel?

Problem jest bardzo jasny. W przypadku relacji jeden-wiele, po stronie "jednej", powinien istnieć tylko jeden rekord, który można jednoznacznie zidentyfikować. Tutaj, myślę, ponieważ id nie jest unikalny, istnieje wiele wpisów.

Możesz spróbować użyć @JoinColumns i dodać obie kolumny, aby jednoznacznie zidentyfikować encję po stronie "one".

@OneToMany 
@JoinColumns({ 
    @JoinColumn(name="yourID1", referencedColumnName="yourID1"), 
    @JoinColumn(name="yourid2", referencedColumnName="yourid2") 
}) 

Zakładam, że masz następujące dane.

tabela A:

id2 c1   id 
100 content1 1000 
101 content2 1001 

tabela B:

id3 s1   id 
100 content1 1000 
101 content2 1000 
102 content3 1001 
103 content4 1001 

Tutaj ID2 i ID3 są unikatowe. A.id jest unikalny, ale b.id nie jest; typowy scenariusz OneToMany.

Jeśli mapie A do B, stosując A.id i B.id, to staje się jeden-do-wielu, w którym A (100) może odnosić się do B (100, 101) identyfikatora 1000

To zadziała dobrze, myślę. Ale jeśli musisz mapować z B na A używając tych samych kolumn (jak podano w pytaniu), to nie zadziała, ponieważ jedna strona (B) ma duplikaty.

Czy poprawnie rozumiem Twoje pytanie?

+0

Przy okazji nie wiem, jak dodać to jako komentarz bez zamieszczania czegoś jako odpowiedzi. Czy ktoś może mi pomóc? –

+0

Hibernacja skarży się po wielu stronach. Mam A.id1, ​​który odwołuje się do B.id1. B.id1 nie jest unikalny (jeden-do-wielu). Hibernate skarży się, że B.id1 jest częścią klucza podstawowego, ale kogo to obchodzi. Dla każdego A.id1 mam więcej B.id1s. Jeśli B.id1 jest również ** częścią ** klucza podstawowego B, nie powinno być istotne. Tabele są powiązane tylko przez id1 (id2 nie istnieje w B). – Matteo

+0

Potrzebujesz reputacji 50, aby móc komentować – Matteo

Powiązane problemy