Pytanie Mapowanie bazy danych tylko do odczytu z relacją wiele do wielu bez tabeli łączenia


Mam pytanie podobne do @ManyToMany bez tabeli łączenia (starsza baza danych) z dodatkowym problemem.

Mam dwie tabele A i B

  • A z kluczem podstawowym z wieloma kolumnami (ID i ID2)
  • B z kluczem podstawowym z wieloma kolumnami (ID i ID3)

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

EDYTOWAĆ: baza danych jest starszą 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, jaki mam, jest to, że oba IDs użyte do łączenia nie są kluczem podstawowym.

Mam następujące klasy:

@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 otrzymuję wiadomości: B.id odwołuje się do pojedynczej właściwości w A (A.id).

EDYTUJ: zgodnie z życzeniem:

public class PrimaryKeysA implements Serializable {

private static final long   serialVersionUID    = 1L;

private int    id1;
private int    id2;

    // getters/setters/equals/hashcode

}

PrimaryKeysB jest podobne z id3 zamiast id2. Obie klasy A i B są uproszczone (anonimizowane) przykłady.


12
2017-12-23 13:19


pochodzenie


Naprawdę nie widzę, jak możesz mieć wiele-do-wielu z tymi tabelami. O identyfikatorze B.ID B.ID i B.ID jest kluczem podstawowym B. Zatem dany A może odnosić się tylko do jednego B. Po prostu masz powiązanie ManyToOne od A do B. - JB Nizet
Ooops przepraszam, że mam to samo na A jak w B. Zmienię to pytanie (próbowałem wygenerować uproszczony przykład posuwający się za daleko) - Matteo
To nie jest wiele do wielu 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? - John Ericksen
@joncarl Nie jest to starsza baza danych tylko do odczytu. W przeciwnym razie wybrałbym lepszy projekt. Mogłem także uniknąć mapowania relacji i po prostu zdefiniować byty. Chciałem go zmapować, aby móc uniknąć wielu wyborów. - Matteo
@joncarl, w rzeczywistości jest to wiele do wielu stowarzyszeń. Dla każdego A istnieje kilka powiązanych B i dla każdego B jest kilka Asów. Projekt jest zły, ale semantycznie jest stowarzyszeniem wielu do wielu. - Matteo


Odpowiedzi:


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

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 następnie zmapuj go w JPA jako ManyToMany z AJOINB jako tabelą złączeń.

Jeśli A.ID2 i B.ID3 byłyby unikatowe same, nie musiałbyś nawet mapować identyfikatorów A.ID i B.ID w komponentach JPA.


4
2018-01-03 15:21



Ponieważ DB jest tylko do odczytu, musiałbym utworzyć nowy DB z kopią wszystkich tabel plus dodatkowy widok (ponieważ 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ć warte ... - Matteo
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
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


Czy możesz udostępnić przykładowe rekordy z twoich 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ą unikalne. A.id jest unikalny, ale b.id nie jest; typowy scenariusz OneToMany.

Jeśli zamapuję A na B, używając Aid i B.id, to staje się to jeden-do-wielu, gdzie A (100) może odnosić się do B (100, 101), jako że id to 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?


2
2017-12-29 06:18



Przy okazji nie wiem, jak dodać to jako komentarz, nie publikując czegoś jako odpowiedzi. Czy ktoś może mi pomóc? - Pragalathan M
Hibernate narzeka na wiele stron. 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 jest również B.id1 część klucza podstawowego B nie powinno mieć znaczenia. Tabele są powiązane tylko przez id1 (id2 nie istnieje w B). - Matteo
Potrzebujesz reputacji 50, aby móc komentować - Matteo
@Matteo Dzięki Matteo - Pragalathan M
@Matteo Czy możesz usunąć skojarzenie B z A i spróbować, aby problem został zawężony? - Pragalathan M