Pergunta

Eu estou usando Hibernate + JPA como minha solução ORM.

Eu estou usando HSQL para testes de unidade e PostgreSQL como o banco de dados real.

Eu quero ser capaz de usar nativo do Postgres UUID tipo com hibernação, e usar o UUID na sua representação Cadeia com HSQL para teste de unidade (desde HSQL não tem um tipo UUID).

Eu estou usando um XML persistência com diferentes configurações para Postgres e HSQL Unidade de Teste.

Aqui está como eu tenho Hibernate "ver" meu costume UserType:

@Id
@Column(name="UUID", length=36)
@org.hibernate.annotations.Type(type="com.xxx.UUIDStringType")
public UUID getUUID() {
    return uuid;
}


public void setUUID(UUID uuid) {
    this.uuid = uuid;
}

e que funciona muito bem. Mas o que eu preciso é a capacidade de trocar a parte "com.xxx.UUIDStringType" da anotação em XML ou a partir de um arquivo de propriedades que podem ser alteradas sem re-compilação.

Todas as idéias?

Foi útil?

Solução

Esta questão é muito antigo e foi respondida por um longo tempo, mas eu recentemente me encontrei na mesma situação e encontrou uma boa solução. Para começar, eu descobri que o Hibernate tem três diferentes built-in tipo implementações UUID:

  1. binary-uuid: armazena o UUID como binário
  2. uuid-char: armazena o UUID como uma sequência de caracteres
  3. pg-uuid: usa o tipo de Postgres UUID nativa

Estes tipos são registrados por padrão e pode ser especificado para um determinado campo com uma anotação @Type, por exemplo.

@Column
@Type(type = "pg-uuid")
private UUID myUuidField;

também um mecanismo para substituir tipos padrão na Dialect. Portanto, se a implantação final é falar com um banco de dados Postgres, mas os testes de unidade usar HSQL, você pode substituir o tipo pg-uuid para ler / escrever dados de caracteres escrevendo um dialeto personalizado assim:

public class CustomHSQLDialect extends HSQLDialect {

    public CustomHSQLDialect() {
        super();

        // overrides the default implementation of "pg-uuid" to replace it
        // with varchar-based storage.
        addTypeOverride(new UUIDCharType() {
            @Override
            public String getName() {
                return "pg-uuid";
            }
        });
    }
}

Agora, basta ligar no dialeto personalizado e do tipo do pg-uuid está disponível em ambos os ambientes.

Outras dicas

Hy, para aqueles que estão à procura de uma solução em Hibernate 4 (porque o método Dialect # addTypeOverride não é mais disponível), eu encontrei um, subjacente em este comentário do Steve Ebersole

Você tem que construir um tipo de usuário personalizada como esta:

public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType {

    public UUIDStringCustomType() {
        super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
    }

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

}

E para ligá-la para o dialeto HSQLDB, é preciso construir um dialeto personalizado que substituir o método Dialect # contributeTypes assim:

public class CustomHsqlDialect extends HSQLDialect {


    @Override
    public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        super.contributeTypes(typeContributions,serviceRegistry);
        typeContributions.contributeType(new UUIDStringCustomType());
    }

}

Em seguida, você pode usar o @type (type = "pg-uuid") com dois bancos de dados.

Hope ele vai ajudar alguém ...

Para evitar problemas entre os tipos UUID sem especificar a anotação @Type (que basicamente significa que você tem que ajustar todas as anotações quando você quer mudar de postgres para mysql ou o contrário ...) Eu estou usando um package-info.java com os hiberna @TypeDef anotação sobre esse pacote.

Aqui está um exemplo de configuração do seu aplicativo:
Assumindo module/src/main/java/app.package.domain contém suas entidades. E você'r testes são armazenados em module/src/test/java/app.package.

Basta criar dois package-info.java em seus pacotes domain.

Certifique-se o pacote-arquivos info são sempre no mesmo pacote (para teste e produção). Veja o seguinte exemplo abaixo:

src/main/java
  app
    package
      domain
        package-info.java 

src/test/java
  app
    package
      domain
        package-info.java 

O conteúdo que você está package-info.java produção deve ficar assim (Postgres):

@TypeDef(
  name = "pg-uuid",
  defaultForType = UUID.class,
  typeClass = PostgresUUIDType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.PostgresUUIDType;

import java.util.UUID;

E é assim você'r testes "configuração" deve ser semelhante (H2):

@TypeDef(
  name = "uuid-char",
  defaultForType = UUID.class,
  typeClass = UUIDCharType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDCharType;

import java.util.UUID;

Hope isso ajuda

Talvez você pode construir alguns smarts no seu tipo de usuário para fazer a coisa certa, dependendo dos recursos de banco de dados. Hibernate em si tem uma abordagem semelhante com seu gerador de ID "nativo", que se comporta de forma diferente dependendo do tipo de banco de dados você está usando. Uma abordagem como isso elimina a necessidade de mudar o mapeamento em tempo de execução.

Por exemplo, você pode criar um classe estratégia para cada banco de dados. Então, em sua classe tipo de usuário, detectar o banco de dados estiver conectado a quando você é chamado pela primeira vez, instanciar a estratégia adequada para esse banco de dados e delegar todas as chamadas para o objeto estratégia.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top