Usando diferentes tipos de usuários do Hibernate, em diferentes situações
-
06-07-2019 - |
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?
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:
-
binary-uuid
: armazena o UUID como binário -
uuid-char
: armazena o UUID como uma sequência de caracteres -
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;
Há 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.