Frage

In Legacy-Datenbanktabellen haben wir Spalten wie C1, C2, C3, C100 oder M1, M2, M3, M100 nummerieren.
Diese Spalten repräsentieren BLOB-Daten.

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

Mit dem JPA Fähiges Kartensuche wir alle Spalten auf einzelne Felder. Und dann außer Kraft setzen wir Namen beim Einbetten unter Verwendung von 100 Überschreibung Anmerkungen.

Vor kurzem haben wechselten wir Hibernate und ich habe Dinge wie UserCollectionType gefunden und CompositeUserType . Aber ich hatte keine Anwendungsfälle nicht gefunden, die Mine nahe sind.

Ist es möglich, einen Benutzer-Typen unter Verwendung von Hibernate implementieren zu können, ein Bündel von Spalten zu einer Sammelstelle zur Karte ohne zusätzliche Abfrage

Bearbeiten
Wie Sie wahrscheinlich die Namen von Spalten bemerkt kann von Tisch zu Tisch unterscheiden. Ich möchte, ohne dass ein Typ wie „LegacyArray“ zu schaffen, die alle den @Columns jedes Mal, wenn ich diese Art verwenden zu spezifizieren. Aber stattdessen würde ich verwenden

  @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;
War es hilfreich?

Lösung

Ich kann 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:

Angenommen, Ihre vorhandene Tabelle primaryentity genannt wird, würde ich eine Ansicht erstellen, die den folgenden ähnlich ist:

-- 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)

Jetzt aus der Ruhe Sicht, childentity ist nur eine normalisierte Tabelle, die einen Fremdschlüssel muss primarykey. Mapping sollte ziemlich geradlinig sein und wird hier abgedeckt:

Die Vorteile dieses Ansatzes:

  • Hibernate Sicht, die Tabellen normalisiert sind, ist es eine ziemlich einfache Zuordnung
  • Kein Updates für Ihre vorhandenen Tabellen

Die Nachteile:

  • wird Daten schreibgeschützt, ich glaube nicht, Ihre Ansicht kann in einer aktualisierbaren Weise definiert werden (ich könnte falsch sein)
  • Benötigt Änderung in der Datenbank, die Sie benötigen viele Ansichten
  • erstellen

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


2. Verwenden Hibernate dynamisches Modell Mapping Einrichtung Ihre C1 abzubilden, C2, C3 Eigenschaften ein Karte und haben einige Code Sie DAO Schicht tut das entsprechende Gespräch zwischen der Karte und der Eigenschaft Collection:

Ich habe nie selbst getan, aber ich glaube, Hibernate Sie Tabellen HashMaps zur Karte zulässt. Ich bin mir nicht sicher, wie dynamisch Hibernate ermöglicht es Ihnen, dies zu tun (dh, Sie können einfach unter Angabe der Tabellennamen weg, und mit Hibernate automatisch alle Spalten Karte?), Aber es ist eine andere Art, wie ich denken kann, dies zu tun.

Wenn jedoch bei diesem Ansatz wird, sollten Sie die Datenzugriffsobjekt Muster rel="nofollow zu verwenden, und sicherzustellen, dass die interne Implementierung (Verwendung von HashMaps) aus dem Client-Code versteckt ist. Auch sicher sein, bevor zu überprüfen, um die Datenbank zu schreiben, dass die Größe der Sammlung nicht die Anzahl der verfügbaren Spalten nicht überschreitet.

Die Vorteile dieses Ansatzes:

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

Die Nachteile:

  • Viele Sanitär in der DAO Schicht der entsprechenden Typen zur Karte
  • Verwendet experimentelle Hibernate Funktionen, die in der Zukunft
  • ändern

Andere Tipps

Ich persönlich denke, dass Design klingt wie es bricht erste Normalform für relationale Datenbanken. Was passiert, wenn Sie C101 oder M101 benötigen? Ändern Sie Ihr Schema wieder? Ich denke, es ist sehr aufdringlich.

Wenn Sie in die Mix Hibernate hinzuzufügen ist es noch schlimmer. Hinzufügen C101 oder M101 bedeutet, dass Sie Ihre Java-Objekte zu ändern, Ihre Hibernate Mappings, alles.

Wenn Sie 1: m Beziehungen mit C- und M-Tabellen, dann würden Sie die Fälle behandeln können, ich durch das Hinzufügen von zusätzlichen Zeilen nur zitiert. Ihre Java-Objekte enthalten Collection oder Collection . Ihre Hibernate Mappings sind Eins-zu-viele, die sich nicht ändern.

Vielleicht ist der Grund, dass Sie nicht alle Hibernate Beispiele sehen, Ihren Fall zu entsprechen, weil es ein Design ist, das nicht empfohlen wird.

Wenn Sie müssen, vielleicht sollte man sich Hibernate Component Mapping .

UPDATE: Die Tatsache, dass dieses Erbe ist gebührend zur Kenntnis genommen. Mein Punkt in der ersten Normalform der Erziehung ist, so viel für andere, die diese Frage in Zukunft finden könnte, wie es für die Person, die die Frage gestellt. Ich möchte nicht, dass die Frage so beantworten, dass es leise, diesen Entwurf als „gut“ geltend gemacht werden.

Unter Hinweis darauf, Hibernate Mapping-Komponente ist relevant, weil der Name zu wissen, was Sie suchen den Schlüssel sein kann, wenn Sie suchen. Hibernate ermöglicht ein Objektmodell als das relationale Modell feinkörnigen, um es abbildet. Sie sind frei, ein denormalisierter Schema (zum Beispiel Name und Adresse Objekte als Teil eines größeren Person-Objekts) zu modellieren. Das ist nur der Name, den sie eine solche Technik geben. Es könnte helfen, auch andere Beispiele.

Sorry, wenn ich Ihr Problem hier bin Missverständnis, ich weiß nicht viel über Hibernate. Aber könnte man nicht nur bei der Auswahl verketten aus der Datenbank so etwas zu bekommen, was Sie wollen?

Wie:

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).

[EDIT] Ich schlage vor, einen CompositeUserType zu verwenden. Hier ist ein Beispiel . Es ist auch ein gutes Beispiel auf Seite 228f in dem Buch „Java Persistence mit Hibernate“.

Das erlaubt Ihnen, die viele Spalten als ein einzelnes Objekt in Java zu handhaben.

Die Abbildung sieht wie folgt aus:

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

Ruhezustand wird alle Spalten während der normalen Abfrage auf einmal 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 müssen Sie eine Liste erstellen und Anschlagelemente hinzugefügt, wenn eine Spalte NULL ist. Für zusätzliche Sicherheit, schlage ich vor, Ihre eigene Liste Umsetzung zu schaffen, die nicht über die Anzahl der Spalten (von ArrayList und Überschreibung ensureCapacity() erbt) wachsen läßt.

[EDIT 2] Wenn Sie nicht alle @Column Anmerkungen eingeben möchten, einen Code-Generator für sie verwenden. Das kann so einfach wie das Skript sein, das Sie einen Namen und eine Nummer geben und er druckt @Column (...) zu System.out. Nachdem das Skript lief, gerade geschnitten und die Daten in die Quelle einfügen.

Die einzige andere Lösung wäre es, die interne Hibernate API für den Zugriff auf diese Informationen zur Laufzeit zu bauen, aber das API ist intern, so viele Sachen privat ist. Sie können Java-Reflexion verwenden und setAccessible(true) aber dieser Code wird wahrscheinlich das nächste Update von Hibernate nicht überleben.

Sie können UserTypes verwenden, um eine bestimmte Anzahl von Spalten auf jede Art abzubilden Sie möchten. Dies könnte eine Sammlung sein, wenn (zum Beispiel) für Sammlungen sind immer in der Größe durch eine bekannte Anzahl von Elementen begrenzt.

Es ist schon eine Weile (> 3 Jahre), seit ich Hibernate verwendet, so bin ich ziemlich rostig, aber ich erinnere mich ist es sehr einfach ist, zu tun; Ihre BespokeUserType Klasse der ResultSet zu Hydrat Ihr Objekt von ihm übergeben wird.

Ich habe auch nie Hibernate verwendet.

Ich schlage vor, ein kleines Programm in einer interpretierten Sprache zu schreiben (wie Python ), in dem Sie eine ausführen String, als ob es ein Befehl. Sie könnten eine Erklärung konstruieren, die aus tun die mühsame Arbeit nimmt, was Sie manuell tun wollen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top