2015-02-18 16 views
22

Zajmuję się tworzeniem aplikacji przy użyciu:Prawidłowe JPA Adnotacja dla PostgreSQL typu tekstowego bez Hibernate Annotations

  • Java 1.7
  • WZP (wliczone w JavaEE-API 7.0)
  • hibernacji 4.3.8.Final
  • PostgreSQL JDBC 9.4-1200-jdbc41
  • PostgreSQL 9.3.6

Chciałbym użyć typu danych PostgreSQL dla niektórych atrybutów String. O ile mi wiadomo, w JPA to powinien być prawidłowy adnotacji, aby użyć tekstu w PostgreSQL:

@Entity 
public class Product{ 
    ... 
    @Lob 
    private String description; 
    .... 
} 

Kiedy opisywanie podmiot, tak, że napotkasz błędy, które wyglądają tak: http://www.shredzone.de/cilla/page/299/string-lobs-on-postgresql-with-hibernate-36.html

W skrócie: Wygląda na to, że hibernacja i jdbc nie idą w parze ze znakami typu clob/text.

Rozwiązanie opisane pracuje:

@Entity 
public class Product{ 
    ... 
    @Lob 
    @Type(type = "org.hibernate.type.TextType") 
    private String description; 
    ... 
} 

Ale to ma znaczący wadę: Źródło potrzeby kod hibernacji w czasie kompilacji, która powinna być zbędna (jest to jeden z powodów, dla użyciem JPA w pierwszej kolejności).

Innym sposobem jest użycie adnotacji kolumny tak:

@Entity 
public class Product{ 
    ... 
    @Column(columnDefinition = "text") 
    private String description; 
    ... 
} 

który działa ładnie, ALE: teraz utknąłem z bazami danych, które mają typ tekstu (i nazywa się również tekst;)) i jeśli w przyszłości będzie używana inna baza danych, adnotacje można łatwo przeoczyć. W związku z tym możliwy błąd może być trudny do znalezienia, ponieważ typ danych jest zdefiniowany w łańcuchu znaków i dlatego nie można go znaleźć przed uruchomieniem.

Czy istnieje rozwiązanie, które jest takie proste, po prostu go nie widzę? Jestem pewien, że nie jestem jedynym użytkownikiem używającym JPA w połączeniu z Hibernate i PostgreSQL. Więc jestem nieco zdezorientowany, że nie mogę znaleźć więcej takich pytań.

Wystarczy wypełnić pytanie, persistence.xml wygląda następująco:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="1.0" 
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
         http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> 
    <persistence-unit name="entityManager"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <class>com.app.model.Product</class> 
    <properties> 
     <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" /> 
     <property name="javax.persistence.jdbc.url" 
     value="jdbc:postgresql://localhost:5432/awesomedb" /> 
     <property name="javax.persistence.jdbc.user" value="usr" /> 
     <property name="javax.persistence.jdbc.password" value="pwd" /> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> 
     <property name="hibernate.jdbc.use_streams_for_binary" value="false" /> 
     <property name="hibernate.hbm2ddl.auto" value="create-drop" /> 
     <property name="show_sql" value="true" /> 
    </properties> 
    </persistence-unit> 
</persistence> 

UPDATE:

+0

Odkąd mówisz o tym, co tak naprawdę jest problemem z instalacją (automatycznie generowanym DDLem), nie możesz po prostu ręcznie utworzyć tabeli jako TEKST w Postgresie i po prostu nie określać niczego w klasie? – chrylis

+0

Tak, chciałbym móc wygenerować DB ze stanu hibernacji. – knoe

+0

A więc ... chcesz użyć niestandardowej funkcji SQL, ale nie chcesz ryzykować niekompatybilności z bazami danych, które nie mają niestandardowej funkcji? – chrylis

Odpowiedz

1

pójdę z prostego private String description;. Typ kolumny jest problemem tylko wtedy, gdy generujesz bazę danych z kodu, ponieważ zostanie wygenerowany jako varchar zamiast text.

Świetnie jest kodować w sposób agnostyczny w bazie danych, bez żadnych specyficznych cech dostawcy WZP, ale są przypadki, w których po prostu nie jest to możliwe. Jeśli rzeczywistość polega na tym, że będziesz musiał obsługiwać wiele typów baz danych ze wszystkimi ich szczegółami, musisz gdzieś je uwzględnić. Jedną z opcji jest użycie columnDefinition do zdefiniowania typu kolumny. Innym jest pozostawienie kodu takim jaki jest, i po prostu zmień typ kolumny w bazie danych. Wolę ten drugi.

+0

Tak, chcę wygenerować DB z kodu. Gdybym go nie potrzebował. Wyliczyłem, że @Column (columnDefinition = "longvarchar") prywatny opis ciągu; Po prostu działa dobrze, ponieważ kombinacja sterownika hibernacji/sterownika jdbc oczekuje tekstu, a nie adresu typu clob. Jaki jest problem z długim/tekstowym błędem z linku. Ale tworzenie tabeli po prostu by się nie powiodło, ponieważ postgresql nie zna typu longvarchar.Gdybym mógł sam zdefiniować alias jak longvarchar = text w PostgreSQL, może to być interesujące ... – knoe

+0

To jest mniej więcej tak samo, jak twoje rozwiązanie, ponieważ columnDefiniton jest używane tylko przy definicji tabeli. – knoe

+0

@knoe: nie ma absolutnie żadnej różnicy między 'varchar' i' text' w Postgresie. –

5

Ponieważ typ text nie jest częścią standardu SQL, nie istnieje żaden oficjalny sposób JPA. Jest to model podobny do varchar, ale bez ograniczenia długości. Można schować wdrażanie WZP z majątku @Columnlength:

@Column(length=10485760) 
private String description; 

Aktualizacja: 10 MiB wydaje się być maksymalna długość varchar w PostgreSQL. text jest prawie nieograniczony, zgodnie documentation:

In any case, the longest possible character string that can be stored is about 1 GB.

+1

Tak, to będzie działać w większości przypadków, gdy tabela nie powinna być generowana przez aplikację. W rezultacie powstaje kolumna PostgreSQL varchar (1000000000). Co jest ograniczone, typ tekstu jest zdefiniowany do przechowywania tekstu bez żadnych ograniczeń. – knoe

+0

O ile wiem, Hibernacja i sterownik jdbc PostgreSQL, nie są w rzeczywistości kompatybilne w tym momencie, hibernacja próbuje uzyskać clob, ponieważ adnotacja lob i sterownik jdbc oferuje zawartość lob nie adres. Nie wiem, która z nich jest właściwa, ale zdecydowanie powinno zaaranżować rozwiązanie, aby użytkownik końcowy mógł z tego korzystać. Bo to jest po prostu brzydkie, aby wpaść w ten problem. – knoe

+1

@knoe: Możesz także użyć 'varchar' bez limitu w Postgresie. W Postgres naprawdę nie ma żadnej różnicy między 'text' lub' varchar', więc po prostu idź z tym, co warstwa zaciemniania działa najlepiej z –

1

Jeśli chcesz używać zwykłego JPA można po prostu przemapować używany typ CLOB na Dialekt jak ten:

public class PGSQLMapDialect extends PostgreSQL9Dialect { 


    @Override 
    public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { 
    if (Types.CLOB == sqlTypeDescriptor.getSqlType()) { 
     return LongVarcharTypeDescriptor.INSTANCE; 
    } 
    return super.remapSqlTypeDescriptor(sqlTypeDescriptor); 
    } 


} 

więc wygrał użyj mapowania CLOB ze sterownika JDBC, który używa identyfikatora OID dla kolumny i przechowuje/ładuje tekst za pomocą obsługi dużych obiektów. To spowodowałoby po prostu wywołanie setString i getString w kolumnie tekstowej kreconej sterownika Postgres JDBC przez klasę VarcharTypeDescriptor.

+0

Wygląda interesująco, spróbuję. Ale nadal nie rozumiem, dlaczego to powinno być w ogóle potrzebne. – knoe

+0

Nie potrzebujesz tego - działa już przy użyciu CLOB ze sterownika JDBC z OID do pracy z ciągiem. Jeśli chcesz zmienić, to lepiej byłoby zaadresować w sterowniku JDBC - imho Hibernate jest w porządku tutaj. –

+0

Wadą użycia właśnie takiego "CLOB-u" jest bardzo słaba wydajność - imho to nie jest w porządku –

Powiązane problemy