Utilisation de différents types d'utilisateurs Hibernate dans différentes situations
-
06-07-2019 - |
Question
J'utilise Hibernate + JPA comme solution ORM.
J'utilise HSQL pour les tests unitaires et PostgreSQL comme base de données réelle.
Je souhaite pouvoir utiliser le UUID tapez avec Hibernate et utilisez l’UUID dans sa représentation String avec HSQL pour les tests unitaires (HSQL n’ayant pas de type UUID).
J'utilise un XML de persistance avec différentes configurations pour les tests d'unité Postgres et HSQL.
Voici comment j'ai mis Hibernate " voir " mon type d'utilisateur personnalisé:
@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;
}
et cela fonctionne très bien. Mais ce qu’il me faut, c’est la possibilité d’échanger le "& com; x.xxx.UUIDStringType". une partie de l'annotation en XML ou à partir d'un fichier de propriétés pouvant être modifié sans recompilation.
Des idées?
La solution
Cette question est vraiment ancienne et on y répond depuis longtemps, mais je me suis récemment retrouvée dans la même situation et j'ai trouvé une bonne solution. Pour commencer, j'ai découvert qu'Hibernate avait trois implémentations de type UUID intégrées différentes:
-
binary-uuid
: stocke l'UUID sous forme binaire -
uuid-char
: stocke l'UUID en tant que séquence de caractères -
pg-uuid
: utilise le type UUID Postgres natif
Ces types sont enregistrés par défaut et peuvent être spécifiés pour un champ donné avec une annotation @Type
, par exemple.
@Column
@Type(type = "pg-uuid")
private UUID myUuidField;
Il existe également un mécanisme permettant de remplacer les types par défaut dans le Dialect
. Donc, si le déploiement final doit communiquer avec une base de données Postgres, mais que les tests unitaires utilisent HSQL, vous pouvez remplacer le type pg-uuid
pour lire / écrire des données de caractères en écrivant un dialecte personnalisé, comme suit:
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";
}
});
}
}
Il suffit maintenant de brancher le dialecte personnalisé et le type pg-uuid
est disponible dans les deux environnements.
Autres conseils
Hy, pour ceux qui recherchent une solution dans Hibernate 4 (car la méthode Dialect # addTypeOverride n’est plus disponible), j’en ai trouvé un, sous-jacent à ce commentaire de Steve Ebersole
Vous devez créer un type d'utilisateur personnalisé comme celui-ci:
public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType {
public UUIDStringCustomType() {
super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
}
@Override
public String getName() {
return "pg-uuid";
}
}
Et pour le lier au dialecte HSQLDB, vous devez créer un dialecte personnalisé qui substitue la méthode Dialect # ContribTypes comme ceci:
public class CustomHsqlDialect extends HSQLDialect {
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions,serviceRegistry);
typeContributions.contributeType(new UUIDStringCustomType());
}
}
Ensuite, vous pouvez utiliser le @Type (type = "pg-uuid") avec les deux bases de données.
J'espère que ça va aider quelqu'un ...
Pour éviter les problèmes entre les types d'UUID sans spécifier l'annotation @Type
(ce qui signifie que vous devez ajuster toutes les annotations lorsque vous souhaitez passer de postgres à mysql ou inversement ... ) J'utilise un package-info.java
avec l'annotation hibernates @TypeDef
sur ce package.
Voici un exemple de configuration de votre application:
En supposant que module / src / main / java / app.package.domain
contient vos entités. Et vos tests sont stockés dans module / src / test / java / app.package
.
Créez simplement deux package-info.java
dans vos packages domain
.
Assurez-vous que les fichiers de paquet-info sont toujours dans le même paquet (pour le test et la production). Voir l'exemple ci-dessous:
src/main/java
app
package
domain
package-info.java
src/test/java
app
package
domain
package-info.java
Le contenu de votre production package-info.java
devrait ressembler à ceci (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;
Et voici comment vous testez la "configuration". devrait ressembler à (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;
J'espère que ça aide
Peut-être pouvez-vous créer des connaissances intelligentes dans votre type d'utilisateur pour faire les choses correctement en fonction des capacités de la base de données. Hibernate lui-même adopte une approche similaire avec son "natif" Générateur d'ID, qui se comporte différemment selon le type de base de données utilisé. Une telle approche élimine le besoin de changer de mappage au moment de l’exécution.
Par exemple, vous pouvez créer une classe stratégie pour chaque base de données. Ensuite, dans votre classe de types d'utilisateurs, détectez la base de données à laquelle vous êtes connecté lorsque vous êtes appelé pour la première fois, instanciez la stratégie appropriée pour cette base de données, puis déléguez tous les appels à l'objet de stratégie.