PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Hibernar UUID com PostgreSQL e SQL Server


Eu tinha requisitos semelhantes, mas também queria usar a geração Hibernate DDL e garantir que o SQL Server gerasse um tipo de identificador exclusivo e também queria oferecer suporte a hsqldb para testes de unidade. , pois a representação binária no SQL Server é para um GUID diferente de um UUID. Veja por exemplo Representação diferente de UUID em Java Hibernate e SQL Server

Você pode criar o mapeamento correto e gerar o sql correto para SQL Server com:
@Type(type = "uuid-char")
@Column(columnDefinition="uniqueidentifier")
public UUID getUuid()

E isso funciona como está, mas infelizmente não há como no Hibernate ter diferentes definições de coluna para bancos de dados diferentes, então isso falhará em qualquer outra coisa que não seja o SQL Server.

Então, você tem que percorrer o caminho mais longo. Isso é tudo para o Hibernate 4.3:
  1. Registre um novo tipo sql GUID em um SQLServerDialect substituído e use esse dialeto em vez do 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. Crie um wrapper UUIDCustomType que se comporte de forma semelhante ao UUIDCharType integrado, mas delegue dependendo do tipo de banco de dados. Você precisa chamar init(databaseType) antes Configuração de hibernação. Talvez o dialeto personalizado possa fazer isso, mas eu chamo isso na inicialização do meu aplicativo Spring.

DatabaseType era um enum que eu já tinha definido com base na configuração do sistema, modifique-o a gosto usando uma classe de dialeto ou string ou qualquer outra coisa.

Esta é uma variação do que está descrito em 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 o tipo personalizado em um local que o Hibernate irá pegar (tenho uma classe base comum para todas as entidades). Eu o registro usando defaultForType =UUID.class para que todos os UUIDs o usem, o que significa que não preciso anotar propriedades UUID.

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

Advertência:na verdade não foi testado com postgres, mas funciona muito bem para hsqldb e sql server no Hibernate 4.3.