Frage

Ich kann nicht Hibernate mit java.util.UUID für PostgreSQL arbeiten.

Hier ist die Abbildung mit javax.persistence * Anmerkungen:.

private UUID itemUuid;

@Column(name="item_uuid",columnDefinition="uuid NOT NULL")
public UUID getItemUuid() {
    return itemUuid;
}

public void setItemUuid(UUID itemUuid) {
    this.itemUuid = itemUuid;
}

Wenn ein vorübergehendes Objekt persistierenden ich eine SQLGrammarException bekommen:

column "item_uuid" is of type uuid but expression is of type bytea at character 149

PostgreSQL Version 8.4.4
JDBC-Treiber - 8.4.4-702 (auch versucht, 9,0 - gleiche)
Hibernate Version ist 3.6, Hauptkonfigurationseigenschaften:

<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.url">jdbc:postgresql://192.168.1.1/db_test</property>
War es hilfreich?

Lösung

Dies kann durch Hinzufügen der folgende Anmerkung zum UUID gelöst werden:

import org.hibernate.annotations.Type;
...
@Type(type="pg-uuid")
private java.util.UUID itemUuid;

Wie, warum nicht Hibernate nicht nur diese Standardeinstellung machen, könnte ich Ihnen nicht sagen ...

UPDATE: Es scheint immer noch Probleme mit der createNativeQuery Methode offene Objekte zu sein, die UUID Felder haben. Zum Glück, so weit das Create Methode hat gut für mich gearbeitet.

Andere Tipps

Sie versuchen Objekt vom Typ UUID zu bestehen, die nicht einheits kommentierten winter. So ist die Hibernate will es Byte-Array (Blob-Typ) serialisiert werden. Aus diesem Grund ist diese Meldung ‚Ausdruck vom Typ bytea‘.

Sie können entweder speichern UUID als Blobs in der Datenbank (nicht elegant), oder geben Sie Ihre individuelle Serializer (viel Arbeit) oder manuell das Objekt konvertieren. UUID-Klasse verfügt über Methoden vonString und toString, so dass ich es als String gespeichert werden soll.

Wie andere schon erwähnt, ist die Lösung für dieses Problem ist es, eine @Type(type = "pg-uuid") Anmerkung hinzuzufügen. Jedoch ist dieser Typ nicht kompatibel mit UUID Typen anderer Hersteller, so dass diese Beziehungen Ihre Hibernate Klassen Postgres. Um dies zu umgehen, ist es möglich, diese Anmerkung zur Laufzeit einfügen. Die folgenden Arbeiten für Hibernate 4.3.7.

Als erstes müssen Sie eine benutzerdefinierte Metadaten-Anbieter einzufügen die Anmerkungen einzufügen. Tun Sie dies als ersten Schritt nach einer Instanz der Configuration Klasse erstellen:

// Perform some test to verify that the current database is Postgres.
if (connectionString.startsWith("jdbc:postgresql:")) {
    // Replace the metadata provider with our custom metadata provider.
    MetadataProviderInjector reflectionManager = MetadataProviderInjector)cfg.getReflectionManager();
    reflectionManager.setMetadataProvider(new UUIDTypeInsertingMetadataProvider(reflectionManager.getMetadataProvider()));
}

Diese benutzerdefinierten Metadaten-Anbieter findet Felder und Methoden des Typs UUID. Wenn es einen findet, fügt es eine Instanz der org.hibernate.annotations.Type Anmerkung besagt, dass der Typ "pg-uuid" sein sollte:

package nl.gmt.data;

import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.common.reflection.AnnotationReader;
import org.hibernate.annotations.common.reflection.MetadataProvider;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

class UUIDTypeInsertingMetadataProvider implements MetadataProvider {
    private final Map<AnnotatedElement, AnnotationReader> cache = new HashMap<>();
    private final MetadataProvider delegate;

    public UUIDTypeInsertingMetadataProvider(MetadataProvider delegate) {
        this.delegate = delegate;
    }

    @Override
    public Map<Object, Object> getDefaults() {
        return delegate.getDefaults();
    }

    @Override
    public AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement) {
        // This method is called a lot of times on the same element, so annotation
        // readers are cached. We only cache our readers because the provider
        // we delegate to also caches them.

        AnnotationReader reader = cache.get(annotatedElement);
        if (reader != null) {
            return reader;
        }

        reader = delegate.getAnnotationReader(annotatedElement);

        // If this element is a method that returns a UUID, or a field of type UUID,
        // wrap the returned reader in a new reader that inserts the "pg-uuid" Type
        // annotation.

        boolean isUuid = false;
        if (annotatedElement instanceof Method) {
            isUuid = ((Method)annotatedElement).getReturnType() == UUID.class;
        } else if (annotatedElement instanceof Field) {
            isUuid = ((Field)annotatedElement).getType() == UUID.class;
        }

        if (isUuid) {
            reader = new UUIDTypeInserter(reader);
            cache.put(annotatedElement, reader);
        }

        return reader;
    }

    private static class UUIDTypeInserter implements AnnotationReader {
        private static final Type INSTANCE = new Type() {
            @Override
            public Class<? extends Annotation> annotationType() {
                return Type.class;
            }

            @Override
            public String type() {
                return "pg-uuid";
            }

            @Override
            public Parameter[] parameters() {
                return new Parameter[0];
            }
        };

        private final AnnotationReader delegate;

        public UUIDTypeInserter(AnnotationReader delegate) {
            this.delegate = delegate;
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
            if (annotationType == Type.class) {
                return (T)INSTANCE;
            }

            return delegate.getAnnotation(annotationType);
        }

        @Override
        public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
            return annotationType == Type.class || delegate.isAnnotationPresent(annotationType);
        }

        @Override
        public Annotation[] getAnnotations() {
            Annotation[] annotations = delegate.getAnnotations();
            Annotation[] result = Arrays.copyOf(annotations, annotations.length + 1);
            result[result.length - 1] = INSTANCE;
            return result;
        }
    }
}

Lösung für jemanden, verwenden JPA nicht.

Bevor:

<property name="testId" >
        <column name="test_id"  sql-type="uuid"  not-null="true"/>
</property>

Nach:

<property name="testId" column="test_id" type="org.hibernate.type.PostgresUUIDType">
</property>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top