sql >> Base de Datos >  >> RDS >> PostgreSQL

Hibernate UUID con PostgreSQL y SQL Server

Tenía requisitos similares, pero también quería usar la generación DDL de Hibernate y asegurarme de que SQL Server generara un tipo de identificador único, y también quería admitir hsqldb para pruebas unitarias. Para usar UUID en SQL Server, definitivamente desea pasar por cadenas no binarias , ya que la representación binaria en SQL Server es para un GUID que es diferente de un UUID. Ver por ejemplo Representación diferente de UUID en Java Hibernate y SQL Server

Puede crear la asignación correcta y generar el sql correcto para SQL Server con:

@Type(type = "uuid-char")
@Column(columnDefinition="uniqueidentifier")
public UUID getUuid()

Y esto simplemente funciona como está, pero desafortunadamente no hay forma en Hibernate de tener diferentes definiciones de columna para diferentes bases de datos, por lo que fallará en cualquier cosa que no sea SQL Server.

Entonces, tienes que ir por el camino más largo. Esto es todo para Hibernate 4.3:

  1. Registre un nuevo tipo GUID sql en un SQLServerDialect anulado y use este dialecto en lugar del base

    public class SQLServer2008UnicodeDialect extends SQLServer2008Dialect
    {
        public SQLServer2008UnicodeDialect() 
        {
            // the const is from the MS JDBC driver, the value is -145
            registerColumnType( microsoft.sql.Types.GUID, "uniqueidentifier" ); 

            // etc. Bonus hint: I also remap all the varchar types to nvarchar while I'm at it, like so:
            registerColumnType( Types.CLOB, "nvarchar(MAX)" );
            registerColumnType( Types.LONGVARCHAR, "nvarchar(MAX)" );
            registerColumnType( Types.LONGNVARCHAR, "nvarchar(MAX)" );
            registerColumnType( Types.VARCHAR, "nvarchar(MAX)" );
            registerColumnType( Types.VARCHAR, 8000, "nvarchar($l)" );
        }
     }
  1. Cree un contenedor UUIDCustomType que se comporte de manera similar al UUIDCharType integrado, pero que delegue según el tipo de base de datos. Debe llamar a init(databaseType) antes Configuración de hibernación. Tal vez el dialecto personalizado podría hacerlo, pero lo llamo en el inicio de mi aplicación Spring.

DatabaseType era una enumeración que ya tenía y que está configurada en función de la configuración del sistema, modifíquela a su gusto usando una clase de dialecto o una cadena o lo que sea.

Esta es una variación de lo que se describe en https://zorq.net/b/2012/04/21/switching-hibernates-uuid-type-mapping-per-database/

public enum DatabaseType
{
    hsqldb,
    sqlserver,
    mysql,
    postgres
}

public class UUIDCustomType extends AbstractSingleColumnStandardBasicType<UUID> implements LiteralType<UUID>
{
    private static final long serialVersionUID = 1L;

    private static SqlTypeDescriptor SQL_DESCRIPTOR;
    private static JavaTypeDescriptor<UUID> TYPE_DESCRIPTOR;

    public static void init( DatabaseType databaseType )
    {
        if ( databaseType == DatabaseType.sqlserver )
        {
            SQL_DESCRIPTOR = SqlServerUUIDTypeDescriptor.INSTANCE;
        }
        else if ( databaseType == DatabaseType.postgres  )
        {
            SQL_DESCRIPTOR = PostgresUUIDType.PostgresUUIDSqlTypeDescriptor.INSTANCE;
        }
        else
        {
            SQL_DESCRIPTOR = VarcharTypeDescriptor.INSTANCE;
        }

        TYPE_DESCRIPTOR = UUIDTypeDescriptor.INSTANCE;
    }

    public UUIDCustomType()
    {
        super( SQL_DESCRIPTOR, TYPE_DESCRIPTOR );
    }

    @Override
    public String getName()
    {
        return "uuid-custom";
    }

    @Override
    public String objectToSQLString( UUID value, Dialect dialect ) throws Exception
    {
        return StringType.INSTANCE.objectToSQLString( value.toString(), dialect );
    }

    public static class SqlServerUUIDTypeDescriptor extends VarcharTypeDescriptor
    {
        private static final long serialVersionUID = 1L;

        public static final SqlServerUUIDTypeDescriptor INSTANCE = new SqlServerUUIDTypeDescriptor();

        public SqlServerUUIDTypeDescriptor()
        {
        }

        @Override
        public int getSqlType()
        {
            return microsoft.sql.Types.GUID;
        }
    }
}
  1. Registre el tipo personalizado en una ubicación que Hibernate recogerá (tengo una clase base común para todas las entidades). Lo registro usando defaultForType =UUID.class para que todos los UUID lo usen, lo que significa que no necesito anotar las propiedades de UUID en absoluto.

    @TypeDefs( {
            @TypeDef( name = "uuid-custom", typeClass = UUIDCustomType.class, defaultForType = UUID.class )
    } )
    public class BaseEntityWithId { 

Advertencia:en realidad no se probó con postgres, pero funciona muy bien para el servidor hsqldb y sql en Hibernate 4.3.