it-swarm.com.de

Bestehende UUID in PostgreSQL mit JPA

Ich versuche, eine Entität in PostgreSQL beizubehalten, die UUID als Primärschlüssel verwendet. Ich habe versucht, es als einfache UUID zu behalten:

@Id
@Column(name = "customer_id")
private UUID id;

Mit dem oben genannten bekomme ich diesen Fehler: 

ERROR: column "customer_id" is of type uuid but expression is of type bytea
Hint: You will need to rewrite or cast the expression.
Position: 137

Ich habe auch versucht, die UUID als Byte [] zu erhalten, ohne Erfolg:

@Transient
private UUID id;

@Id
@Column(name = "customer_id")
@Access(AccessType.PROPERTY)
@Lob
protected byte[] getRowId() {
    return id.toString().getBytes();
}

protected void setRowId(byte[] rowId) {
    id = UUID.fromString(new String(rowId));
}

Wenn ich @Lob entferne, ist der Fehler der gleiche wie oben. Wenn @Lob angewendet wird, ändert sich der Fehler jedoch geringfügig in:

ERROR: column "customer_id" is of type uuid but expression is of type bigint
Hint: You will need to rewrite or cast the expression.
Position: 137

Ich fühle mich extrem schlecht, weil ich nichts so einfaches wie dieses tun kann! 

Ich verwende Hibernate 4.1.3.Final mit PostgreSQL 9.1. 

Ich habe zahlreiche Fragen zu SO mehr oder weniger mit dem gleichen Thema gesehen, aber sie sind alle alt und keine scheint eine direkte Antwort zu haben. 

Ich möchte dies auf eine standardisierte Weise erreichen, ohne auf hässliche Hacks zurückzugreifen. Aber wenn dies nur durch (hässliche) Hacks erreicht werden kann, dann werde ich das vielleicht auch tun. Ich möchte jedoch die UUID nicht als varchar in der Datenbank speichern, da dies für die Leistung nicht gut ist. Außerdem möchte ich, wenn möglich, keine Abhängigkeit von Hibernate in meinen Code einfügen.

Jede Hilfe wäre sehr dankbar.

UPDATE 1 (2012-07-03 12:15 Uhr)

Nun, nun ja ... Es ist schon interessant, dass ich den gleichen Code (einfache UUID, keine Konvertierung - die erste Version des oben genannten Codes) mit SQL Server 2008 R2 mit dem JTDS-Treiber (v1.2.5) und getestet habe , weißt du was, es hat als Zauber geholfen (natürlich musste ich verbindungsbezogene Informationen in persistence.xml ändern). 

Ist es ein PostgreSQL-spezifisches Problem oder was?

24
ehsanullahjan

Der PostgreSQL-JDBC-Treiber hat sich leider für die Darstellung von Nicht-JDBC-Standardcodes entschieden. Sie ordnen einfach alle zu Types.THER zu. Um es kurz zu machen: Sie müssen eine spezielle Hibernate-Typzuordnung für die Verarbeitung von UUID-Zuordnungen aktivieren (in Spalten des postgres-spezifischen uuid-Datentyps):

@Id
@Column(name = "customer_id")
@org.hibernate.annotations.Type(type="org.hibernate.type.PostgresUUIDType")
private UUID id;

oder prägnanter:

@Id
@Column(name = "customer_id")
@org.hibernate.annotations.Type(type="pg-uuid")
private UUID id;

Eine weitere (bessere) Option ist das Registrieren von org.hibernate.type.PostgresUUIDType als Standardzuordnung des Hibernate-Typs für alle als Java.util.UUID bereitgestellten Attribute. Dies wird in der Dokumentation @ http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch06.html#types-registry behandelt.

32
Steve Ebersole

JPA 2.1 bietet eine sehr einfache Möglichkeit, den PostgreSQL-Spaltentyp uuid und Java.util.UUID als Typ des entsprechenden Entitätsfelds zu verwenden:

@javax.persistence.Converter(autoApply = true)
public class PostgresUuidConverter implements AttributeConverter<UUID, UUID> {

    @Override
    public UUID convertToDatabaseColumn(UUID attribute) {
        return attribute;
    }

    @Override
    public UUID convertToEntityAttribute(UUID dbData) {
        return dbData;
    }

}

Fügen Sie diese Klasse einfach zu Ihrer Persistenzkonfiguration hinzu und kommentieren Sie die UUID-Felder mit @Column(columnDefinition="uuid").

15
Oleg Estekhin

Damit es mit Hibernate 5.1.x funktioniert, können Sie Steve Ebersole hier kommentieren folgen.

@Id
@GeneratedValue
@Column( columnDefinition = "uuid", updatable = false )
public UUID getId() {
    return id;
}
6
Christophe

Eine neuere Version >= 8.4-701 des Postgresql-JDBC-Treibers verarbeitet Java.util.UUID-Zuordnung korrekt. Und auch Hibernate >= 4.3.x.

Details finden Sie unter https://stackoverflow.com/a/780922/173149 :

Map the database uuid type to Java.util.UUID.
This only works for relatively new server (8.3) and JDK (1.5) versions.
2
gavenkoa

Die von Oleg vorgeschlagene Lösung hat für mich nicht perfekt funktioniert (sie schlug fehl, wenn Sie einen Nullwert beibehalten wollten). Hier ist eine optimierte Lösung, die auch für Nullwerte funktioniert.

In meinem Fall verwende ich jedoch EclipseLink, wenn Sie also Hibernate verwenden, benötigen Sie dies möglicherweise nicht.

public class UuidConverter implements AttributeConverter<UUID, Object> {
    @Override
    public Object convertToDatabaseColumn(UUID uuid) {
        PGobject object = new PGobject();
        object.setType("uuid");
        try {
            if (uuid == null) {
                object.setValue(null);
            } else {
                object.setValue(uuid.toString());
            }
        } catch (SQLException e) {
            throw new IllegalArgumentException("Error when creating Postgres uuid", e);
        }
        return object;
    }

    @Override
    public UUID convertToEntityAttribute(Object dbData) {
        return (UUID) dbData;
    }
}
1
Ixim

Fügt dieses Flag bei der Postgresql-URL-Verbindung hinzu:? Stringtype = nicht angegeben

so wie das

jdbc: postgresql: // localhost: 5432/Ihre Datenbank? stringtype = nicht angegeben

0
user8157076