Использование UUID с EclipseLink и PostgreSQL

Я хочу использовать тип uuid PostgreSQL для объектов первичные ключи. За что ямы создали конвертер (реализующий интерфейс конвертера). Ниже приведен соответствующий код:

    @Override
    public void initialize(DatabaseMapping mapping, Session session) {
        final DatabaseField field;
        if (mapping instanceof DirectCollectionMapping) {
            field = ((DirectCollectionMapping) mapping).getDirectField();
        } else {
            field = mapping.getField();
        }

        field.setSqlType(Types.OTHER);
        field.setTypeName("uuid");
        field.setColumnDefinition("UUID");
    }

Затем я'мы аннотировали соответствующую сущность X нижеуказанными аннотациями:

@Converter(name="uuidConverter",converterCalss=UUIDConverter.class)
@Convert("uuidConverter")
@Id
public UUID getId()
{
    return id;
}

Проблема в том, что у меня есть другой класс (Y), который имеет следующее определение:

@ManyToOne(targetEntity = X.class)
@JoinColumn(name = "x_id")
public X getX();

Хотя EclipseLink создал таблицы, как и ожидалось, он отправляет строку в базу данных при попытке вставить объекты типа Y. Postgres возвращает следующее сообщение об ошибке:

column "id" is of type uuid but expression is of type character varying at character

Любые решения / обходные пути будут оценены.

 Adam Gent12 нояб. 2012 г., 16:28
У меня были такие проблемы, как раньше, и я просто использовал строку для UUID (то есть uuid.toString ()), которая варьируется от 36 символов.

Ответы на вопрос(5)

У меня были некоторые проблемы с EclipseLink JPA 2.1 + Postgresql + UUID в качестве первичного ключа, но я нашел другое решение. Я принял AttributeConverter, но столкнулся с проблемой в реализации EclipseLink, которую я решил с помощью этого кода:

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

    @Override
    public Object convertToDatabaseColumn(UUID uuid) {
        PostgresUuid object = new PostgresUuid();
        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) {
        if (dbData instanceof String) {
            return UUID.fromString(dbData.toString());
        } else {    
            return (UUID) dbData;
        }
    }

}


public class PostgresUuid extends PGobject implements Comparable {

    private static final long serialVersionUID = 1L;

    @Override
    public int compareTo(Object arg0) {
        return 0;
    }

}

Как я подробно объяснил в этом постеhttp://blog-ungarida.rhcloud.com/persisting-uuid-in-postgresql-using-jpa-eclipselink/

Решение Вопроса

У меня была та же проблема с EclipseLink JPA + Postgresql + UUID в качестве первичного ключа.

Чтобы решить это, яМы объединили коды из Github и ссылки ниже:https://forums.oracle.com/forums/thread.jspa?messageID=4584157

Приведенный ниже код для UUIDConverter работал у меня, хотя код наверняка нет самый лучший.

public void initialize(DatabaseMapping ARGMapping, Session ARGSession)
{
    final DatabaseField Field;
    if (ARGMapping instanceof DirectCollectionMapping)
    {
        Field = ((DirectCollectionMapping) ARGMapping).getDirectField();
    }
    else
    {
        Field = ARGMapping.getField();
    }
    Field.setSqlType(Types.OTHER);
    Field.setTypeName("uuid");
    Field.setColumnDefinition("UUID");

    for (DatabaseMapping m : ARGMapping.getDescriptor().getMappings())
    {
        assert OneToOneMapping.class.isAssignableFrom(ManyToOneMapping.class);
        if (m instanceof OneToOneMapping)
        {
            for (DatabaseField field : ((OneToOneMapping) m).getForeignKeyFields())
            {
                field.setSqlType(Types.OTHER);
                field.setColumnDefinition("UUID");
                field.setTypeName("uuid");
            }
        }
    }
}
 TR4NQUILLITY26 февр. 2013 г., 13:08
Просто не уверен, что ответ правильный или нет.
 Ja͢ck26 февр. 2013 г., 13:13
я отредактировал его, чтобы он выглядел больше как ответ, а яубрал понижающий голос :)
 Ja͢ck26 февр. 2013 г., 13:22
Я нене понимаю, невежливо к кому?
 Royce06 янв. 2016 г., 01:17
ПРЕДУПРЕЖДЕНИЕ. Приведенный выше код небезопасен, цикл по сопоставлениям изменяет сопоставления полей всех полей, участвующих в сопоставлениях OneToOne, от объекта с UUID на нем - он должен касаться только тех полей, которые содержат UUID. Используя код выше васпосмотрим такие вещи:eclipse.org/forums/...
 TR4NQUILLITY26 февр. 2013 г., 13:09
Кроме того, код работает, все еще может рассматриваться как ответ.
 markdsievers25 нояб. 2013 г., 22:47
С EclipseLink 2.4 это нет совсем работа. Изменяя его на `field.setSqlType (Types.OTHER); field.setType (UUID.class); field.setColumnDefinition (»UUID»); `сделал свое дело.

Универсальный UUIDConverter для EclipseLink (не только PostgreSQL)

Код:

import java.nio.ByteBuffer;
import java.util.UUID;

import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;

public class UUIDConverter implements Converter {

    private Boolean isUUIDasByteArray = true;

    @Override
    public Object convertObjectValueToDataValue(Object objectValue,
                                                Session session) {
        if (isUUIDasByteArray) {
            UUID uuid = (UUID)objectValue;
            if (uuid == null) return null;
            byte[] buffer = new byte[16];
            ByteBuffer bb = ByteBuffer.wrap(buffer);
            bb.putLong(uuid.getMostSignificantBits());
            bb.putLong(uuid.getLeastSignificantBits());
            return buffer;
        }
        return objectValue;
    }

    @Override
    public UUID convertDataValueToObjectValue(Object dataValue,
                                              Session session) {
        if (isUUIDasByteArray) {
            byte[] bytes = (byte[])dataValue;
            if (bytes == null) return null;
            ByteBuffer bb = ByteBuffer.wrap(bytes);
            long high = bb.getLong();
            long low = bb.getLong();
            return new UUID(high, low);
        }
        return (UUID) dataValue;
    }

    @Override
    public boolean isMutable() {
        return true;
    }

    @Override
    public void initialize(DatabaseMapping mapping, Session session) {
        final DatabaseField field;
        if (mapping instanceof DirectCollectionMapping) {
            // handle @ElementCollection...
            field = ((DirectCollectionMapping) mapping).getDirectField();
        } else {
            field = mapping.getField();
        }

        if (session != null && session.getLogin()!= null && session.getLogin().getPlatform() != null) {
            String platform = session.getLogin().getPlatform().getClass().getSimpleName();

            if (platform.equals("PostgreSQLPlatform")) {
                field.setSqlType(java.sql.Types.OTHER);
                field.setTypeName("java.util.UUID");
                field.setColumnDefinition("UUID");
                isUUIDasByteArray = false;
            } else if (platform.equals("H2Platform")) {
                field.setColumnDefinition("UUID");
            } else if (platform.equals("OraclePlatform")) {
                field.setColumnDefinition("RAW(16)");
            } else if (platform.equals("MySQLPlatform")) {
                field.setColumnDefinition("BINARY(16)");
            } else if (platform.equals("SQLServerPlatform")) {
                field.setColumnDefinition("UNIQUEIDENTIFIER");
            }
        }

    }
}

Ты неМне нужен обращенный. Используйте это определение столбца в сущности. Вы должны сначала зарегистрировать расширение uuid. Это работает с Postgres 10 и Wildfly 10.1

@Column(name = "UUID", nullable=false, insertable = false, columnDefinition="uuid DEFAULT uuid_generate_v4()")
private String uuid;

Попробуйте проверить, что fieldClassification сопоставления находится в методе initialize. Это может быть как-то получение String.class, попробуйте установить его в Object.class.

или field.setType (Object.class)

 Avner Levy12 нояб. 2012 г., 17:23
мы попробовали это, и это неТ помочь. После отладки кода похоже, что конвертер работает долгое время после обработки отношений (MetadataProject :: processStage3). Другие идеи?
 Avner Levy12 нояб. 2012 г., 16:45
Я думаю, что проблема в том, что обработка many2one происходит до запуска конвертеров (фаза входа в систему). Поэтому, когда он проверяет первичный ключ принадлежащего объекта, он неt включить соответствующую информацию о типе. Есть идеи?
 Chris12 нояб. 2012 г., 17:02
Основы и конвертеры обрабатываются в первую очередь для разрешения идентификаторов перед связями. Вы можете проверить с помощью контрольных точек, но япопробую Джеймса предложение первым.

Ваш ответ на вопрос