2009-07-15 4 views
2

In älteren Datenbanktabellen haben wir nummerierte Spalten wie C1, C2, C3, C100 oder M1, M2, M3, M100.
Diese Spalten repräsentieren BLOB-Daten.Kartendatenbank spalte1, spalte2, spalteN zu einer Sammlung von Elementen

Es ist nicht möglich, diese Datenbank zu ändern.

Mithilfe von JPA Embeddable ordnen wir alle Spalten einzelnen Feldern zu. Und während des Einbettens überschreiben wir Namen mit 100 Override-Annotationen.

Vor kurzem haben wechselten wir Hibernate und ich habe Dinge wie UserCollectionType und CompositeUserType gefunden. Aber ich habe keine Anwendungsfälle gefunden, die meinen ähneln.

Ist es möglich, einige Benutzertypen mit Hilfe von Hibernate zu implementieren, um ein Bündel von Spalten einer Sammlung zuordnen zu können ohne zusätzliche Abfrage?

Edit:
Wie Sie wahrscheinlich die Namen von Spalten bemerkt kann von Tisch zu Tisch unterscheiden. Ich möchte einen Typ wie "LegacyArray" erstellen, ohne dass ich alle @Columns jedes Mal angeben muss, wenn ich diesen Typ verwende. Aber stattdessen würde ich

@Type(type = "LegacyArrayUserType", 
     parameters = 
    { 
     @Parameter(name = "prefix", value = "A"), 
     @Parameter(name = "size", value = "128") 
    }) 
    List<Integer> legacyA; 

    @Type(type = "LegacyArrayUserType", 
     parameters = 
    { 
     @Parameter(name = "prefix", value = "B"), 
     @Parameter(name = "size", value = "64") 
    }) 
    List<Integer> legacyB; 

Antwort

3

ich von ein paar Möglichkeiten denken, dass ich dies tun würde.

1. Erstellen Sie Ansichten für die Sammlung Informationen, die eine normalisierte Tabellenstruktur simuliert, und wo es sich als eine Sammlung Hibernate:

Ihre vorhandenen Tabelle Angenommen wird primaryentity genannt, würde ich eine Ansicht erstellen, die ähnlich ist die folgend:

-- untested SQL... 
create view childentity as 
(select primaryentity_id, c1 from primaryentity union 
select primaryentity_id, c2 from primaryentity union 
select primaryentity_id, c3 from primaryentity union 
--... 
select primaryentity_id, c100 from primaryentity) 

nun aus der Ruhe Sicht, childentity ist nur eine normalisierte Tabelle, die einen Fremdschlüssel zu primarykey hat. Die Abbildung dieser nach vorne ziemlich gerade sein sollte, und wird hier abgedeckt:

Die Vorteile dieses Ansatzes:

  • Von Hibernate Sicht sind die Tabellen normalisiert, es ist eine ziemlich einfache Zuordnung
  • Keine Aktualisierungen Ihrer vorhandenen Tabellen

Die Nachteile:

  • Daten schreibgeschützt ist, ich glaube nicht, Ihrer Ansicht nach in einer aktualisierbaren Weise definiert werden kann (ich könnte falsch sein)
  • Benötigt in der Datenbank ändern, die Sie benötigen schaffen viele Ansichten

Alternativ, wenn Ihr DBA lassen Sie nicht einmal einen Blick in die Datenbank aufzunehmen, oder wenn Sie Updates durchführen müssen:


2. Verwenden Sie Hibernate dynamic model mapping facility Ihre C1 abzubilden, C2, C3 Eigenschaften zu einem Map, und haben einige Code, den Sie Ihre DAO Schicht tun das entsprechende Gespräch zwischen der Karte und der Eigenschaft Collection:

Ich habe dies nie getan ich, aber ich glaube, Hibernate erlaubt Ihnen, Tabellen zu HashMaps zuzuordnen. Ich bin mir nicht sicher, wie dynamisch Hibernate dies ermöglicht (d. H., Können Sie einfach den Tabellennamen angeben und Hibernate automatisch alle Spalten zuordnen?), Aber es ist eine andere Art, wie ich das tun kann.

Wenn Sie jedoch mit diesem Ansatz arbeiten, stellen Sie sicher, dass Sie das data access object Muster verwenden, und stellen Sie sicher, dass die interne Implementierung (Verwendung von HashMaps) vor dem Clientcode verborgen ist. Vergewissern Sie sich vor dem Schreiben in die Datenbank, dass die Größe Ihrer Sammlung die Anzahl der verfügbaren Spalten nicht überschreitet.

Die Vorteile dieses Ansatzes:

  • Keine Änderung an der Datenbank an allen
  • Daten ist aktualisierbar
  • O/R Mapping
  • relativ einfach ist

Die Nachteile:

  • Viele Rohrleitungen in der DAO-Laye r die entsprechenden Typen
  • Verwendet experimentelle Hibernate Funktionen abzubilden, die
  • in Zukunft ändern kann
+0

Das Problem ist, ich möchte nicht alle Namen von mir selbst angeben. –

+0

Vielleicht war ich nicht klar in meiner Antwort, aber ich denke nicht, dass Sie in jedem Fall würden. Welche Option hast du angeschaut? –

+0

"... ordnen Sie Ihre C1, C2, C3 Eigenschaften einer Karte zu ...". Dazu muss ich alle Spaltennamen angeben, oder habe ich etwas übersehen? –

0

Sie können UserType s verwenden verwenden, um eine bestimmte Anzahl von Spalten auf jede Art Sie wollen abzubilden. Dies könnte eine Sammlung sein, wenn (zum Beispiel) für Sammlungen immer eine bestimmte Anzahl von Elementen in der Größe begrenzt ist.

Es ist eine Weile her (> 3 Jahre) seit ich Hibernate benutzt habe, also bin ich ziemlich eingerostet, aber ich erinnere mich, dass es sehr einfach ist; Ihre BespokeUserType Klasse wird die ResultSet zu Hydrat Ihr Objekt von ihm übergeben.

+0

Danke für die Antwort. Könnten Sie bitte den Abschnitt "Bearbeiten" lesen und bestätigen, dass dies möglich ist? –

1

Persönlich denke ich, dass Design klingt wie es first normal form für relationale Datenbanken bricht. Was passiert, wenn Sie C101 oder M101 benötigen? Ändern Sie Ihr Schema erneut? Ich denke, es ist sehr aufdringlich.

Wenn Sie Hibernate zum Mix hinzufügen, ist es noch schlimmer. Das Hinzufügen von C101 oder M101 bedeutet, dass Sie Ihre Java-Objekte, Ihre Hibernate-Mappings, alles ändern müssen.

Wenn Sie 1: m-Beziehungen mit C- und M-Tabellen haben, können Sie die Fälle, die ich gerade zitiert habe, durch Hinzufügen zusätzlicher Zeilen bearbeiten. Ihre Java-Objekte enthalten Collection <C> oder Collection <M>. Ihre Hibernate-Zuordnungen sind Eins-zu-Viele, die sich nicht ändern.

Vielleicht der Grund, warum Sie keine Hibernate-Beispiele sehen, die zu Ihrem Fall passen, da es sich um ein Design handelt, das nicht empfohlen wird.

Wenn Sie müssen, sollten Sie vielleicht Hibernate Component Mapping betrachten.

UPDATE: Die Tatsache, dass dies Erbe ist, wird ordnungsgemäß zur Kenntnis genommen. Mein Punkt, wenn ich die erste normale Form aufbringe, ist für andere, die diese Frage in der Zukunft finden könnten, genauso wie für die Person, die die Frage gestellt hat. Ich möchte die Frage nicht so beantworten, dass sie diesen Entwurf stillschweigend als "gut" bezeichnet.

Es wird darauf hingewiesen, dass das Zuordnen von Hibernate-Komponenten wichtig ist, da Sie wissen, wonach Sie suchen. Hibernate ermöglicht ein feinkörnigeres Objektmodell als das relationale Modell, das es abbildet. Sie können ein denormalisiertes Schema modellieren (z. B. Namens- und Adressobjekte als Teil eines größeren Person-Objekts). Das ist nur der Name, den sie einer solchen Technik geben. Es könnte helfen, andere Beispiele zu finden.

+0

Ich denke du verpasst den Punkt der Frage. Er sagte nicht, das sei ein gutes oder neues Design. Er sagte, es sei ein Legacy-Design. Ich musste auch für so etwas kodieren. Am Ende habe ich ein @ Embeddable erstellt, das nur Collection und Iterable implementiert. Aber ich denke, ich werde zurückgehen und es als UserType neu implementieren, die auf eine Kernsammlung verweist. Das einzige Problem mit benutzerdefinierten UserTypes ist, dass es keine gute Dokumentation gibt, wie man sie effizient implementiert. d. h. Hashcode und anderes Vergleichsverhalten mit Hibernate, um eine Aktualisierung auf keine "effektive" Änderung zu vermeiden. – DragonFax

+0

Ich glaube nicht, dass ich es tat. Ich habe "Vermächtnis" bemerkt. Mit der Hibernate-Komponentenzuordnung können Sie eine beliebige Anzahl von Spalten in einer Tabelle aufnehmen, sie in einem Objekt einkapseln (z. B. Name im Beispiel) und sie zu Elementdaten in einem größeren Objekt machen. Ich habe UserTypes implementiert und finde die Dokumentation für Hashcode und so. Sie sollten "Identitätssemantik" befolgen. – duffymo

+0

Danke für die Antwort. Natürlich klingt es wie ein schlechtes Design. Wenn wir nur das Schema ändern könnten. Obwohl ich mir nicht sicher bin, ob etwas mit der ersten Normalform zu tun hat. Es gibt keine wiederholenden Gruppen. Alle diese N Spalten sind wie BLOB. Wie auch immer, könnten Sie den Abschnitt "Bearbeiten" lesen und bestätigen, dass dies möglich ist? –

1

Tut mir leid, wenn ich dein Problem hier falsch verstehe, ich weiß nicht viel über Hibernate. Aber könnten Sie nicht einfach während der Auswahl aus der Datenbank verketten, um etwas zu bekommen, was Sie wollen?

Like:

SELECT whatever 
    , C1||C2||C3||C4||...||C100 AS CDATA 
    , M1||M2||M3||M4||...||M100 AS MDATA 
FROM ... 
WHERE ... 

(Natürlich ist der Verkettungsoperator unterscheidet zwischen RDBMS.)

+0

Ich brauche Zuordnungen zur Entität und nicht nur Anweisung auswählen. –

1

[EDIT] Ich schlage vor, einen CompositeUserType zu verwenden. Here is an example. Es gibt auch ein gutes Beispiel auf Seite 228f im Buch "Java Persistence mit Hibernate".

Damit können Sie die vielen Spalten als ein einzelnes Objekt in Java behandeln.

Die Abbildung sieht wie folgt aus:

@org.hibernate.annotations.Columns(columns = { 
    @Column(name="C1"), 
    @Column(name="C2"), 
    @Column(name="C3"), 
    ... 
}) 
private List<Integer> c; 

Hibernate alle Spalten auf einmal während der normalen Abfrage geladen werden.

In Ihrem Fall müssen Sie die int-Werte aus der Liste in eine feste Anzahl von Spalten in nullSafeSet kopieren. Pseudo-Code:

for (int i=1; i<numColumns; i++) 
    if (i < list.size()) 
     resultSet.setInt(index+i, list.get(i)); 
    else 
     resultSet.setNull(index+i, Hibernate.INTEGER.sqlType()); 

In nullSafeGet Sie eine Liste erstellen müssen und Anschlagelemente hinzugefügt, wenn eine Spalte NULL ist. Für zusätzliche Sicherheit schlage ich vor, Ihre eigene Listenimplementierung zu erstellen, die es nicht erlaubt, über die Anzahl der Spalten hinaus zu wachsen (erben von ArrayList und überschreiben ensureCapacity()).

[EDIT2] Wenn Sie nicht alle @Column-Annotationen eingeben möchten, verwenden Sie einen Codegenerator für sie. Das kann so einfach sein wie ein Skript, dem Sie einen Namen und eine Nummer geben, und es druckt @Column (...) auf System.out. Nachdem das Skript ausgeführt wurde, schneiden Sie einfach & die Daten in die Quelle ein.

Die einzige andere Lösung wäre, auf die interne Hibernate-API zuzugreifen, um diese Informationen zur Laufzeit zu erstellen, aber diese API ist intern, so dass viele Dinge privat sind. Sie können Java Reflection und setAccessible(true) verwenden, aber dieser Code wird wahrscheinlich die nächste Aktualisierung von Hibernate nicht überleben.

+0

POJO sollte als POJO verlassen werden. Ich mag die Idee nicht, um Domänenobjekte zu erzeugen. Ich habe nur eine normale Art der Legacy-Kapselung. –

+0

Ein POJO ist ein POJO, egal, ob Sie es geschrieben haben oder ob der Computer es für Sie geschrieben hat. Sind Sie ein Handwerker oder ein Softwareentwickler? Automatisieren Sie, was Sie können, um effizienter zu sein. –

+0

Was "... generieren abstrakte Basisklassen, die Sie von ... ableiten" ist das? Ich möchte nicht, dass ein Geschäftsobjekt von einer generierten Schnittstelle abgeleitet wird (deshalb habe ich POJO erwähnt). –

0

Ich habe auch nie Hibernate verwendet.

Ich empfehle, ein kleines Programm in einer interpretierten Sprache (wie Python) zu schreiben, in dem Sie eine Zeichenfolge ausführen können, als wäre es ein Befehl. Sie könnten eine Anweisung konstruieren, die Ihnen die mühsame Aufgabe abnimmt, das zu tun, was Sie manuell tun möchten.

+0

Ich brauche ein Java-Objekt, das der Tabelle zugeordnet ist. Ich kann nicht sehen, wie Python eingebettet werden kann, um solche Dinge zu lösen. –

Verwandte Themen