PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Hiberner UUID avec PostgreSQL et SQL Server

J'avais des exigences similaires, mais je voulais également utiliser la génération Hibernate DDL et m'assurer que SQL Server générait un type d'identifiant unique, et je voulais également prendre en charge hsqldb pour les tests unitaires. Pour utiliser les UUID dans SQL Server, vous voulez absolument passer par des chaînes non binaires , car la représentation binaire dans SQL Server correspond à un GUID différent d'un UUID. Voir par exemple Représentation différente de l'UUID dans Java Hibernate et SQL Server

Vous pouvez créer le mappage correct et générer le sql correct pour SQL Server avec :

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

Et cela fonctionne tel quel, mais malheureusement, il n'y a aucun moyen dans Hibernate d'avoir différentes définitions de colonne pour différentes bases de données, donc cela échouera sur autre chose que SQL Server.

Donc, il faut aller loin. C'est tout pour Hibernate 4.3 :

  1. Enregistrer un nouveau type GUID sql dans un SQLServerDialect remplacé et utiliser ce dialecte au lieu de celui de 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. Créez un wrapper UUIDCustomType qui se comporte de la même manière que le UUIDCharType intégré mais qui délègue en fonction du type de base de données. Vous devez appeler init(databaseType) avant Configuration d'hibernation. Peut-être que le dialecte personnalisé pourrait le faire, mais j'appelle cela au démarrage de mon application Spring.

DatabaseType était une énumération que j'avais déjà définie en fonction de la configuration du système, modifiez-la à votre goût en utilisant une classe ou une chaîne de dialecte ou autre.

Il s'agit d'une variante de ce qui est décrit sur 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. Enregistrez le type personnalisé dans un emplacement qu'Hibernate récupérera (j'ai une classe de base commune pour toutes les entités). Je l'enregistre en utilisant defaultForType =UUID.class afin que tous les UUID l'utilisent, ce qui signifie que je n'ai pas du tout besoin d'annoter les propriétés UUID.

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

Mise en garde :pas réellement testé avec postgres, mais fonctionne très bien pour hsqldb et sql server sur Hibernate 4.3.