2016-08-20 1 views
9

Mit Spring Boot Starter versuche ich ein einfaches Beispielprojekt zu erstellen, das einen Benutzer mit mehreren enthält Adressfelder. Ich experimentiere mit @DiscriminatorColumn und @DiscriminatorValue, um die verschiedenen Arten von Adressen zu unterscheiden, die ein Benutzer haben kann. HierERROR Tabelle mit diesem Namen [Benutzer_Adresse] ist bereits Entität zugeordnet, wenn dieselbe Join-Tabelle verwendet wird, um auf Unterklassen einer verknüpften Entität zu verweisen

ist eine gekürzte Auswahl der Tabellen in meinem Projekt:

CREATE TABLE user (id INT AUTO_INCREMENT); 
CREATE TABLE user_address (user_id INT, address_id INT); 
CREATE TABLE address (id INT AUTO_INCREMENT, TYPE VARCHAR(31)); 

Und hier sind die Klassen Ich versuche zu verbinden:

@Entity 
@DiscriminatorColumn(name = "type") 
public class Address { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 
    private String type; 
} 

@Entity 
@DiscriminatorValue("HOME") 
public class HomeAddress extends Address {} 

@Entity 
@DiscriminatorValue("CURRENT") 
public class CurrentAddress extends Address{} 

@Entity 
public class User { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 
    private String type; 

    @OneToOne 
    @JoinTable(
     name = "user_address", 
     joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, 
     inverseJoinColumns = {@JoinColumn(name = "address_id", referencedColumnName = "id")} 
    ) 
    private HomeAddress homeAddress; 

    @OneToOne 
    @JoinTable(
     name = "user_address", 
     joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, 
     inverseJoinColumns = {@JoinColumn(name = "address_id", referencedColumnName = "id")} 
    ) 
    private CurrentAddress currentAddress; 

} 

Ich habe versucht, @OneToOne mit @OneToMany ersetzt aber trotzdem funktioniert es nicht.

Der Grund, warum ich dies tun möchte, ist, dass ich daran denke, eine Adresse mit anderen Entitäten zu verbinden. Zum Beispiel Shipping für einen Auftrag oder LocationAddress für ein Gebäude usw.

Hier ist ein Dump des Fehlers:

Caused by: org.hibernate.boot.spi.InFlightMetadataCollector$DuplicateSecondaryTableException: Table with that name [user_address] already associated with entity 
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl$EntityTableXrefImpl.addSecondaryTable(InFlightMetadataCollectorImpl.java:1420) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.cfg.annotations.EntityBinder.addJoin(EntityBinder.java:972) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.cfg.annotations.EntityBinder.addJoin(EntityBinder.java:868) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.cfg.ClassPropertyHolder.addJoin(ClassPropertyHolder.java:207) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1792) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:904) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:731) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final] 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final] 
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:338) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE] 
    ... 16 common frames omitted 
+0

Konzeptionell entspricht eine Lieferadresse einer Heimadresse und einer Rechnungsadresse. Warum brauchen Sie unterschiedliche konkrete Implementierungen? – christopher

+0

Sie sollten das Fehlerprotokoll in Ihre Frage einfügen, da es möglicherweise in der Zeit mit externen Hosts verschwindet. – davidxxx

+0

Gemeinsame Beziehungen sind nicht Teil der JPA-Spezifikation. Ihre Verwendung ist nicht portabel und JPA-Provider-spezifisch. FWIW –

Antwort

1

Ihr Fehler ist:

Caused by: org.hibernate.boot.spi.InFlightMetadataCollector$DuplicateSecondaryTableException: Table with that name [user_address] already associated with entity

Sie forgoten haben die @Inheritance Anmerkung. Ich nehme an, dass Sie eine einzige Tabelle für alle Adressklassen verwenden. Sie sollten also präzisieren, dass Sie eine SINGLE_TABLE Strategie für die Handhabung von OOP-> SQL-Mapping verwenden möchten. Es ist standardmäßig verwendet, aber Sie können es seit besser lesbar.

es auf der Klassendeklaration Ihrer Superklasse Einheit hinzufügen: @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

auf diese Weise:

@Entity 
@DiscriminatorColumn(name = "type") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public class Address { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 
    private String type; 
} 

Edit:

user_address als jointable in mehreren Beziehungen verwendet in die User Einheit. Hibernate vermittelt den Eindruck, dass es dies nicht akzeptiert.

Wenn Sie eine einzelne Beziehung verwenden, verlieren Sie die Vorteile, die Adressen zu kategorisieren.
Wenn Sie Ihr Schema ändern können, können Sie die Join-Tabelle entfernen und eine fk-Adresse hinzufügen, um die userId anzugeben. Entschuldigung, ich habe keine anderen Hinweise.

+0

Leider gibt es immer noch die gleiche Fehlermeldung. –

+0

Entschuldigung. Ich habe meine Antwort bearbeitet – davidxxx

+0

Ich schätze die Mühe, mir zu helfen. –

2

Leider können Sie keine separaten Beziehungen für die beiden Adresstypen erstellen, da reine JPA-Ergebnisse von Joins in Abfragen nicht "diskriminieren" können, dh keine Joins mit dem Diskriminatorwert zum Abrufen von nur Objekten eines bestimmten Objekts vornehmen Geben Sie für eine Assoziation und für die andere Assoziation einen anderen Typ ein. Hibernate verfügt stattdessen über Methoden, um es zu tun, aber außerhalb der JPA-Spezifikation.

So ist die einzige Art und Weise funktioniert es ist so dass Sie eine @OneToMany Beziehung mit Adresse Objekte haben, können Sie im Gegenzug eine polymorphe Sammlung geben wiederum HomeAddress und CurrentAddress Objekte

enthält hade ich ein ähnliches Problem.Die einzige Lösung für mich war, ein bisschen anders zu arbeiten (und zwar auf eine Art, die ich nicht so mochte, aber das war's).

Grundsätzlich haben Sie 4 Möglichkeiten (und mehrere Alternativen):

1- nur ein (@OneToMany) Verhältnis, scannen Sie Ihre Sammlung für Objekte vom Typ HomeAddress und/oder CurrentAddress nach abrufen und ordnen sie die richtigen Felder .

2- Ändern Sie die Art, wie Ihre Vererbung entworfen wird. In diesem Fall können Sie Adresse als @MappedSuperclass und Ihre Unterklassen als Entitäten verwenden, die die Adressklasse erweitern. Die zwei Klassen sollten in zwei getrennten Tabellen zugeordnet werden. Sie benötigen keine Join-Tabelle. So ging ich weiter, auch wenn es mir nicht so gut gefallen hat.

3- wegzuwerfen Vererbung und verwendet 2 separate Tabellen

4- Verwendung Ruhezustand (nicht-JPA) Anmerkungen.

Sorry für die nicht Einfügen von Code, aber ich bin nicht in der Lage, es zu tun hier & jetzt

1

Haben Sie das Attribut versucht

@ManyToMany

Da with this definition Sie archivieren, was Sie haben

A and B in which A may contain a parent instance for which there are many children in B and vice versa.

Verwandte Themen