2016-07-28 12 views
5

Ich denke, ich versuche, etwas wirklich einfaches zu tun. Spring-Boot (1.3.3.RELEASE) mit JPA verwenden Ich möchte einen Tabellennamen festlegen.Legen Sie den Tabellennamen im Frühling JPA

@Entity 
@Table(name = "MyTable_name") 
public class MyTableData { 
    ... 
} 

Was ich in meiner Datenbank erwarte, ist eine Tabelle mit "MyTable_name". Scheint mir völlig vernünftig. Aber das passiert nicht. Ich bekomme eine Tabelle mit dem Namen "MY_TABLE_NAME" (H2-Backend) oder "my_table_name" (Postgre-Backend). Ab hier bleibe ich bei Postgre, da ich eine vorhandene DB lesen möchte, in der ich die Tabellennamen nicht kontrolliere.

Nach einigen Recherchen finde ich Beiträge, die sagen, dass ich die spring.jpa.hibernate.naming-Strategie-Eigenschaft verwenden sollte. Das hilft nicht viel. Die Einstellung auf die am häufigsten empfohlene org.hibernate.cfg.ImprovedNamingStrategy erzeugt das gleiche Verhalten: "my_table_name". Die Einstellung auf "org.hibernate.cfg.EJB3NamingStrategy" erzeugt "meinTabellenname". Die Einstellung auf org.hibernate.cfg.DefaultNamingStrategy verursacht Anwendungskontextfehler in Spring-Innereien.

Resigniert, um mein eigenes zu schreiben, fing ich an, org.hibernate.cfg.ImprovedNamingStrategy zu betrachten. Ich entdeckte, dass es die veraltete org.hibernate.cfg.NamingStrategy verwendet. Dies schlägt vor, stattdessen NamingStrategyDelegator zu verwenden. Ich schaute auf seine Java docs aber nicht sicher, wie man sich bewirbt. Ich habe this post gefunden. So sehr ich die Erklärung auch schätze, was zu tun ist, ist komplexer als das, was ich brauche, und ich hatte Schwierigkeiten, es anzuwenden.

Meine Frage ist dann, wie kann ich Spring JPA bekommen, nur den Namen zu verwenden, den ich spezifiziere? Gibt es eine neue Eigenschaft für NamingStrategyDelegator? Muss ich meine eigene Strategie schreiben?

=========== aktualisieren ==========================

Ich glaube, ich Ich konvergiere auf eine Antwort. Ich habe eine einfache Spring-Startanwendung erstellt (getrennt von meinem Produktionsprojekt). Ich benutze H2 für die Backend-DB.

This discussion auf Hiberate 5 Naming ist sehr hilfreich. Damit habe ich herausgefunden, wie man Benennungsstrategien in Hibernate 5 wie folgt definiert (in application.properties).

hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl 
hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 

habe ich eine physische Namensstrategie, die durch den Namen übergeben (wie org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl der Fall ist) und Werte ausgibt. Von diesem sehe ich, dass Tabellennamen sind, was ich durch die physische Benennungsschicht will.

Ich legte dann Hibernate.show_sql = True zu zeigen, SQL zu generieren. Im generierten SQL sind die Namen auch korrekt.

Ich untersuche Tabellennamen mit DatabaseMetaData.

Ich sehe immer noch Tabellennamen in ALLEN CAPS, wenn ich den obigen Code verwende. Das führt mich zu der Annahme, dass DatabaseMetaData aus irgendeinem Grund Großbuchstaben zeigt, aber der Rest des Codes verwendet die richtigen Namen. [EDIT: Diese Schlussfolgerung ist nicht korrekt. Ich war nur verwirrt von allem anderen, was passierte. Späteres Testen zeigt, dass DatabaseMetaData Tabellennamen mit korrektem Groß-/Kleinbuchstaben anzeigt.]

Dies ist noch keine vollständige Antwort, da ich noch etwas Fremdheit in meinem Produktionscode habe, das ich untersuchen muss. Aber es ist nah dran und ich wollte ein Update veröffentlichen, damit potenzielle Leser keine Zeit verlieren.

Hier ist meine Pass durch physikalische Benennungsstrategie, falls jemand interessiert ist. Ich weiß, dass es helfen kann, zu sehen, was andere getan haben, besonders wenn man versucht, Klassen und Pakete im Labyrinth des Frühlings zu finden.

package my.domain.eric; 

import java.io.Serializable; 

import org.hibernate.boot.model.naming.Identifier; 
import org.hibernate.boot.model.naming.PhysicalNamingStrategy; 
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class NamingStrategyPhysicalLeaveAlone implements PhysicalNamingStrategy, Serializable { 
    private static final long serialVersionUID = -5937286882099274612L; 

    private static final Logger LOGGER = LoggerFactory.getLogger(NamingStrategyPhysicalLeaveAlone.class); 

    protected Logger getLogger() { 
     return LOGGER; 
    } 

    @Override 
    public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) { 
     String nameText = name == null ? "" : name.getText(); 
     getLogger().info("toPhysicalCatalogName name: {}", nameText); 
     return name; 
    } 

    @Override 
    public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) { 
     String nameText = name == null ? "" : name.getText(); 
     getLogger().info("toPhysicalSchemaName name: {}", nameText); 
     return name; 
    } 

    @Override 
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { 
     String nameText = name == null ? "" : name.getText(); 
     getLogger().info("toPhysicalTableName name: {}", nameText); 
     return name; 
    } 

    @Override 
    public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) { 
     String nameText = name == null ? "" : name.getText(); 
     getLogger().info("toPhysicalSequenceName name: {}", nameText); 
     return name; 
    } 

    @Override 
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { 
     String nameText = name == null ? "" : name.getText(); 
     getLogger().info("toPhysicalColumnName name: {}", nameText); 
     return name; 
    } 
} 
+0

Welchen JPA-Anbieter verwenden Sie? Welche Version? Dein ursprünglicher Code sollte funktionieren. Wenn Sie bereits Tabellen haben, warum generieren Sie die DDL? Es muss etwas anderes geben, das den Tabellennamen für Sie erstellt, da das, was Sie haben, direkt aus dem Hibernate [docs] (https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity) stammt .html # entity-mapping-entity) oder OpenJPA [docs] (https://openjpa.apache.org/builds/2.4.1/apache-openjpa/docs/manual.html#jpa_overview_mapping_table). – JudgingNotJudging

+0

Ich benutze Hibernate 4.3.11.Final. Ich bin mir nicht sicher, warum du denkst, ich erzeuge die DDL (ich bin mir nicht einmal sicher, was du damit meinst). Ich habe eine Entität erstellt, in der Daten gelesen werden können. Meine Tabellen befinden sich bereits in einer vorhandenen Datenbank. Ich habe Tests, die die Datenbank mit H2 simulieren (sie erzeugen Tabellen und ich möchte, dass sie dieselben Namen wie die Tabellen in der realen Datenbank haben). "Es muss etwas anderes geben, das die Tabellennamen erzeugt". Ja, das ist genau meine Frage: Was in Spring/JPA/Hibernate/????? meckert mit meinem erklärten Namen? Und wie repariere ich es? – EricGreg

+0

Ich habe auch Testcode gegen PostgreSQL ausgeführt und somit Tabellen generiert. Vielleicht sind das und meine H2-Kommentare der Grund, warum du denkst, dass ich "die DDL erzeuge". In meinen Tests möchte ich den korrekten Tabellennamen generieren. In meinem Produktionscode möchte ich, dass meine Lese- und Abfragevorgänge auf die korrekten vorhandenen Tabellen verweisen. – EricGreg

Antwort

3

Die Antwort auf meine Frage angegeben.

  1. SQL ist case insensitive, aber es ist nicht ganz so einfach. Zitierte Namen werden wörtlich genommen. Unbenannte Namen können frei interpretiert werden. Zum Beispiel konvertiert PostgreSQL nicht abgekürzte Namen in Kleinbuchstaben, während H2 sie in Großbuchstaben umwandelt. Wählen Sie also * aus MyTable_name in PostgreSQL sucht nach Tabelle Mytable_name. In H2 sucht dieselbe Abfrage nach MYTABLE_NAME. In meinem Fall wurde die PostgreSQL-Tabelle mit einem in Anführungszeichen gesetzten Namen "MyTable_name" erstellt, so dass * aus MyTable_name fehlschlägt, während die Auswahl von * aus "MyTable_name" erfolgreich ist.
  2. Spring JPA/Hibernate übergibt nicht benannte Namen an SQL.
  3. Im Frühjahr JPA/Hibernate gibt es drei Methoden, die verwendet werden können, zitiert Namen
    1. Explizit den Namen zitieren weitergeben müssen: @Table (name = "\" MyTable_name \ "")
    2. eine physikalische Namensgebung Implement Strategie, die Namen zitiert (Details unten)
    3. Legen Sie ein undokumentiertes Attribut fest, um alle Tabellen- und Spaltennamen zu zitieren: spring.jpa.properties.hibernate.globally_quoted_identifiers = true (siehe this comment). Letzteres ist, was ich getan habe, weil ich auch Spaltennamen habe, für die ich die Groß-/Kleinschreibung beachten muss.

Eine weitere Quelle der Verwirrung für mich war, dass viele Websites auf die alte Namensgebung Variable hibernate.ejb.naming_strategy beziehen oder es ist Frühling gleichwertig. Für Hibernate 5 ist das veraltet. Stattdessen, wie ich in meiner Frage update erwähnt habe, hat Hibernate 5 implizite und physische Benennungsstrategien.

Außerdem war ich verwirrt, weil es Winterschlafeigenschaften gibt und dann gibt es Spring-Eigenschaften. Ich benutzte this very helpful tutorial. Es zeigt jedoch die unnötige direkte Verwendung von Hibernate-Eigenschaften (wie ich in meinem Update auflisten) und dann explizite Konfiguration von LocalContainerEntityManagerFactoryBean und JpaTransactionManager. Viel einfacher zu verwenden Spring Eigenschaften und lassen sie automatisch abgeholt werden. Relevant für mich sind die Benennungsstrategien.

  1. spring.jpa.hibernate.naming.implicit-Strategie
  2. spring.jpa.hibernate.naming.physical-Strategie

eine physische Namensstrategie umzusetzen man eine Klasse erstellen muss, dass implementiert org.hibernate.boot.model.naming.PhysicalNamingStrategy, wie ich in meinem Update oben zeige. Das Angeben von Namen ist eigentlich sehr einfach, da die an die Methode übergebene Identifier-Klasse das Angeben verwaltet oder nicht. Daher wird die folgende Methode Tabellennamen angeben.

Andere Dinge, die ich gelernt habe, könnten hilfreich für jemanden sein, der hier nach Antworten suchte.

  1. Mit spring.jpa Eigenschaften Auto wählt SQL-Dialekt. Bei direktem Hibernate hatte ich SQL-Fehler, als ich zu Postgre wechselte.
  2. Obwohl Fehler im Zusammenhang mit Spring-Anwendungskontexten sehr häufig auftreten, deutet das sorgfältige Lesen der Fehler oft auf Lösungen hin.
  3. DatabaseMetaData meldet Tabellennamen korrekt, ich war nur von allem anderen verwirrt.
  4. Legen Sie spring.jpa.show-sql = true fest, um generiertes SQL zu sehen. Sehr hilfreich beim Debuggen. Erlaubt mir zu sehen, dass korrekte Tabellennamen verwendet werden
  5. spring.jpa.hibernate.ddl-auto unterstützt mindestens die folgenden Werte. create-drop: Tabellen beim Eintritt erstellen, beim Verlassen fallen lassen. create: erstellt Tabellen beim Eintritt, aber bleibt beim Verlassen stehen. keine: nicht erstellen oder löschen. Ich habe gesehen, dass Leute "update" als Wert verwenden, aber das ist für mich fehlgeschlagen. (Zum Beispiel here.) Hier ist ein discussion on the options.
  6. Ich hatte Probleme in H2 mit zitierten Spaltennamen, aber nicht weiter untersucht.
  7. Spring properties page ist hilfreich, aber Beschreibungen sind sehr spärlich.
0

Der Name wird in der Entity-Anmerkung beinhaltet die folgenden

@Entity(name = "MyTable_name") 
public class MyTableData { 
    ... 
} 
+0

Für die [Dokumente] (https://docs.oracle.com/javaee/6/api/javax/persistence/Entity.html) wird dieser "Name" in Abfragen verwendet, nicht für die Benennung von Tabellen. > Der Name der Entität. Standardmäßig wird der nicht qualifizierte Name der Entitätsklasse verwendet. Dieser Name wird verwendet, um auf die Entität in Abfragen zu verweisen. Der Name darf kein reserviertes Literal in der Java Persistence-Abfragesprache sein. – JudgingNotJudging

+0

Ich habe versucht, auf diese Weise, aber es funktioniert immer noch nicht. – odin88

Verwandte Themen