sql >> Databáze >  >> RDS >> PostgreSQL

Hibernujte UUID s PostgreSQL a SQL Serverem

Měl jsem podobné požadavky, ale také jsem chtěl použít generování Hibernate DDL a ujistit se, že SQL Server vygeneroval typ uniqueidentifier, a také jsem chtěl podporovat hsqldb pro testování jednotek. Chcete-li používat UUID v SQL Server, určitě chcete procházet řetězce, které nejsou binární , protože binární reprezentace v SQL Server je pro GUID, který se liší od UUID. Viz například Odlišná reprezentace UUID v Java Hibernate a SQL Server

Můžete vytvořit správné mapování a vygenerovat správný sql pro SQL Server pomocí:

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

A funguje to tak, jak je, ale bohužel v režimu spánku neexistuje způsob, jak mít různé definice sloupců pro různé databáze, takže to selže na čemkoli jiném než na SQL Server.

Takže musíte jít dlouhou cestu kolem. To je vše pro Hibernate 4.3:

  1. Zaregistrujte nový typ GUID sql v přepsaném SQLServerDialect a použijte tento dialekt místo základního

    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. Vytvořte obal UUIDCustomType, který se chová podobně jako integrovaný UUIDCharType, ale deleguje jej v závislosti na typu databáze. Musíte zavolat init(databaseType) před Konfigurace hibernace. Možná by to mohl udělat vlastní dialekt, ale já tomu říkám ve svém spuštění aplikace Spring.

DatabaseType byl výčet, který jsem již měl a který je nastaven na základě konfigurace systému, upravte jej podle chuti pomocí dialektové třídy nebo řetězce nebo čehokoli jiného.

Toto je variace toho, co je popsáno na 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. Zaregistrujte vlastní typ v umístění, které Hibernate převezme (mám společnou základní třídu pro všechny entity). Registruji jej pomocí defaultForType =UUID.class, takže jej používají všechna UUID, což znamená, že vlastnosti UUID nemusím vůbec komentovat.

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

Upozornění:není ve skutečnosti testováno s postgres, ale funguje skvěle pro server hsqldb a sql na Hibernate 4.3.



  1. Definováno omezení ODLOŽIT PŮVODNĚ OKAMŽITĚ je stále ODLOŽENO?

  2. Mohu použít návratovou hodnotu INSERT...RETURNING v jiném INSERTu?

  3. Chyba MySql:Nelze aktualizovat tabulku v uložené funkci/spouštěči, protože ji již používá příkaz, který tuto uloženou funkci/spouštěč vyvolal

  4. Proč Postgres nepoužívá index?