2016-08-08 72 views
0

Ich habe eine praktische Beziehung eingerichtet, in der eine Entität eine Eins-zu-viele-Beziehung mit einer anderen hat, und das hat eine Eins-zu-Eins-Beziehung mit einer anderen . So hat ein LISTING viele LISTING_LINE_ITEMS, und diese LISTING_LINE_ITEMS haben ein SERVICE_PERIOD, aber ein SERVICE_PERIOD hat viele LISTING_LINE_ITEMS. Ich habe versucht, diese Beziehung @JoinTable der Verwendung von JPA wie folgt zu beschreiben:JPA Inverse Join mit OneToMany verursacht Mehr als eine Zeile mit der angegebenen ID

LISTING

@OneToMany 
@JoinTable (name = "LISTING_LINE_ITEM", joinColumns = @JoinColumn (name = "listing_id"), inverseJoinColumns = @JoinColumn (name = "service_period_id")) 
Set<ServicePeriod>      servicePeriods; 

LISTING_LINE_ITEM

@ManyToOne (fetch = FetchType.EAGER) 
@JoinColumn (name = "listing_id", nullable = false) 
Listing     listing; 

@ManyToOne (fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) 
@JoinColumn (name = "service_period_id") 
ServicePeriod    servicePeriod; 

SERVICE_PERIOD

@ManyToOne 
@JoinTable (name = "LISTING_LINE_ITEM", joinColumns = @JoinColumn (name = "service_period_id"), inverseJoinColumns = @JoinColumn (name = "listing_id")) 
Listing    listing; 

Die offensichtliche Ziel der Lage sein leicht erhalten Sie eine Liste von ServicePeriod s für eine Listing oder eine einzelne Listing für eine ServicePeriod. Derzeit ist die Art und Weise dies eingerichtet ist, ich eine Ausnahme bin immer:

org.hibernate.HibernateException: More than one row with the given identifier was found: 361951, for class: com.gonfind.entity.ServicePeriod 

Ich glaube, das liegt daran, dass ein Eintrag ListingLineItems hat, die mit demselben ServicePeriod beziehen. Ich bin mir sicher, dass es einen Weg gibt, das zu erreichen, was ich will, aber ich weiß nicht, was es ist.

+1

Sie sagen, dass viele Werbebuchungen die gleiche Serviceperiode haben können. Sie versuchen jedoch, die indirekte Beziehung von Auflistungen über Werbebuchungen zu Servicezeiträumen als Eins-zu-Viele und nicht als Viele-zu-Viele zu modellieren. Ist es daher richtig, daraus abzuleiten, dass hier eine zusätzliche Einschränkung besteht: Mehrere Werbebuchungen können der gleichen Serviceperiode zugeordnet sein, vorausgesetzt, dass sie alle derselben Auflistung * zugeordnet sind? –

+0

@JohnBollinger ja, das ist richtig. – lmerry213

+0

Hat jede Werbebuchung einen Servicezeitraum oder können Werbebuchungen ohne (null) Servicezeitraum vorhanden sein? –

Antwort

1

Sie scheinen dort einige Probleme zu haben. Auf der technischen/JPA Seite:

  • Sie können nicht LISTING_LINE_ITEM sowohl als Join-Tabelle verwenden und als Einheit Tabelle. Es gibt mehrere Gründe dafür, aber der Hauptgrund ist, dass Sie JPA verwirren: Es wird versuchen, diese Tabelle auf verschiedene, inkompatible Weise für diese beiden Zwecke zu verwenden.

  • in JPA gehört eine bidirektionale Beziehung genau einer Seite; Die andere Seite verwendet das Attribut mappedBy ihrer Beziehungsanmerkung, um auf die besitzende Seite zu verweisen.

Aber Sie haben auch Daten Design-Probleme. Ihre Einschränkung, dass Positionen Dienstzeiten zu einem von denen separat mit der gleichen Kotierung beschränkt werden bildet entweder

  • eine funktionale Abhängigkeit zwischen Nicht-Schlüsselfeldern, wenn die Auflistung ID nicht Teil der Position Schlüssels oder

  • eine funktionale Abhängigkeit von einer Teilmenge eines Schlüssels.

Im ersten Fall sind Ihre Daten nicht in der dritten Normalform; im zweiten Fall sind sie nicht einmal in der zweiten Normalform. Ihr Problem, dies mit JPA zu modellieren, ergibt sich teilweise aus dem niedrigen Normalisierungsgrad.

Wenn Sie Ihre Daten normalisieren, wird das auf mehreren Ebenen viel einfacher. Dazu müssen Sie die direkte Verknüpfung zwischen Einträgen und Werbebuchungen entfernen und sie stattdessen über Servicezeiträume verknüpfen.Sie würden dann haben:

Listing < - one to many ->ServicePeriod < - one to many ->LineItem

Natürlich, die Auswirkungen auf die Struktur Ihrer Anwendung haben würden, aber es ist wahrscheinlich ein langfristiger Entwicklungs- und Wartungsgewinn und vielleicht sogar ein Usability-Gewinn, damit die Anwendung so auf die natürliche Struktur Ihrer Daten ausgerichtet wird. Wenn Sie möchten, können Sie Methoden auf Ihre Listing Einheit setzen, um zu erlauben, dass ListingLineItem s zu einem gewissen Grad so verwaltet werden, als gehörten sie direkt zu Listing s und umgekehrt.

Diese Datenorganisation würde wie folgt aussehen:

LISTING

@OneToMany(mappedBy = "listing", 
     fetch = FetchType.EAGER, 
     cascade = CascadeType.PERSIST) 
Set<ServicePeriod> servicePeriods; 

SERVICE_PERIOD

@ManyToOne(fetch = FetchType.EAGER) 
@JoinColumn(name = "listing_id") 
Listing listing; 

@OneToMany(mappedBy = "servicePeriod", 
     fetch = FetchType.EAGER, 
     cascade = CascadeType.PERSIST) 
Set<ListingLineItem> lineItems; 

LISTING_LINE_ITEM

@ManyToOne(fetch = FetchType.EAGER) 
@JoinColumn(name = "service_period_id") 
ServicePeriod servicePeriod; 

Wenn Sie Ihre Daten nicht mehr oder weniger so umstrukturieren können, dann sind Sie stecken Jerry-Rigging etwas, das nicht vollständig zu JPA beschrieben werden kann. Ich stelle mir eine separate Join-Tabelle für Listing < ->ServicePeriod vor, eine Nicht-JPA-FK-Einschränkung für diese Tabelle aus der Entitätstabelle für Einzelposten und natürlich die richtige Form für die verschiedenen bidirektionalen Beziehungen.

+0

Danke, das war immens hilfreich. Ich habe dieses Schema nicht entworfen, und obwohl ich mit Datendesign und normalen Formen nicht gut vertraut bin, ist diese Anwendung noch nicht in Produktion und ich denke, das Refactoring des Schemas ist wahrscheinlich die richtige Entscheidung. Ich werde etwas lesen und vielleicht werde ich meine endgültige Lösung veröffentlichen. – lmerry213