PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Hibernate UUID mit PostgreSQL und SQL Server

Ich hatte ähnliche Anforderungen, aber ich wollte auch die Hibernate-DDL-Generierung verwenden und sicherstellen, dass SQL Server einen Uniqueidentifier-Typ generiert, und außerdem hsqldb für Unit-Tests unterstützen , da die binäre Darstellung in SQL Server für eine GUID gilt, die sich von einer UUID unterscheidet. Siehe zum Beispiel Unterschiedliche Darstellung der UUID in Java Hibernate und SQL Server

Sie können die richtige Zuordnung erstellen und die richtige SQL für SQL Server generieren mit:

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

Und das funktioniert einfach wie es ist, aber leider gibt es in Hibernate keine Möglichkeit, unterschiedliche Spaltendefinitionen für verschiedene Datenbanken zu haben, also wird dies auf irgendetwas anderem als SQL Server fehlschlagen.

Sie müssen also den langen Weg gehen. Das ist alles für Hibernate 4.3:

  1. Registrieren Sie einen neuen GUID-SQL-Typ in einem überschriebenen SQLServerDialekt und verwenden Sie diesen anstelle des Basisdialekts

    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. Erstellen Sie einen Wrapper UUIDCustomType, der sich ähnlich wie der eingebaute UUIDCharType verhält, aber je nach Datenbanktyp delegiert. Sie müssen init(databaseType) vorher aufrufen Hibernate-Konfiguration. Vielleicht könnte der benutzerdefinierte Dialekt es tun, aber ich nenne das in meinem Spring-App-Startup.

DatabaseType war eine Aufzählung, die ich bereits hatte und die basierend auf der Systemkonfiguration festgelegt wurde. Modifizieren Sie sie nach Belieben mit einer Dialektklasse oder einem String oder was auch immer.

Dies ist eine Variation dessen, was unter https://zorq.net/b/2012/04/21/switching-hibernates-uuid-type-mapping-per-database/

beschrieben wird
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. Registrieren Sie den benutzerdefinierten Typ an einem Ort, den Hibernate abholen wird (ich habe eine gemeinsame Basisklasse für alle Entitäten). Ich registriere es mit defaultForType =UUID.class, damit alle UUIDs es verwenden, was bedeutet, dass ich überhaupt keine UUID-Eigenschaften annotieren muss.

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

Vorbehalt:Nicht wirklich mit Postgres getestet, funktioniert aber hervorragend für hsqldb und SQL Server unter Hibernate 4.3.