Question

Dans les tableaux de base de données existants, nous avons numéroté colonnes comme C1, C2, C3, C100 ou M1, M2, M3, M100.
Ces colonnes représentent les données BLOB.

Il est impossible de changer quoi que ce soit il cette base de données.

En utilisant JPA intégrable nous dressons la carte toutes les colonnes à un seul champs. Et puis lors de l'intégration, nous remplaçons les noms en utilisant 100 annotations override.

Récemment, nous avons passé à Hibernate et je l'ai trouvé des choses comme UserCollectionType et CompositeUserType . Mais je ne l'avais pas trouvé de cas d'utilisation qui sont proches de moi.

Est-il possible de mettre en œuvre un certain type d'utilisateur en utilisant Hibernate pour pouvoir cartographier un ensemble de colonnes à une collection sans interrogation supplémentaire ?

Edit: Comme vous l'avez sans doute remarqué les noms de colonnes peuvent différer de table en table. Je veux créer un type comme « LegacyArray » sans avoir besoin de spécifier tous les annotation @Columns chaque fois que j'utilise ce type. Mais au lieu que je utiliser

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "A"),
      @Parameter(name = "size", value = "128")
   })
   List<Integer> legacyA;

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "B"),
      @Parameter(name = "size", value = "64")
   })
   List<Integer> legacyB;
Était-ce utile?

La solution

Je peux penser à deux façons que je ferais cela.

1. Créer des vues pour les informations de collection qui simule une structure de table normalisée et la carte à Hibernate comme une collection:

En supposant que votre table existante est appelée primaryentity, je créerais une vue qui est similaire à ce qui suit:

-- untested SQL...
create view childentity as
(select primaryentity_id, c1 from primaryentity union
select primaryentity_id, c2 from primaryentity union
select primaryentity_id, c3 from primaryentity union
--...
select primaryentity_id, c100 from primaryentity)

Maintenant du point de vue de mise en veille prolongée, childentity est juste une table normalisée qui a une clé étrangère à primarykey. CARTOGRAPHIE cela devrait être assez simple, et est couvert ici:

Les avantages de cette approche:

  • Du point de vue de mise en veille prolongée, les tables sont normalisées, il est une application assez simple
  • Aucune mise à jour vos tables existantes

Les inconvénients:

  • Les données sont en lecture seule, je ne pense pas que votre point de vue peut être définie de manière actualisable (je peux me tromper)
  • nécessite un changement de la base de données, vous devrez peut-être créer beaucoup de vues

Par ailleurs, si votre DBA ne sera même pas vous permettre d'ajouter une vue à la base de données, ou si vous devez effectuer des mises à jour:


2. Utilisez la fonction modèle dynamique mapping Hibernate pour carte votre C1, C2, C3 propriétés à Carte , et avoir un code votre couche OAC faire la conversation appropriée entre la carte et la propriété Collection:

Je ne l'ai jamais fait moi-même, mais je crois que Hibernate ne vous permet de cartographier les tables de HashMaps. Je ne sais pas comment dynamiquement Hibernate vous permet de le faire (par exemple, Pouvez-vous vous en sortir avec spécifiant simplement le nom de la table, et Hibernate carte automatiquement toutes les colonnes?), Mais il est une autre façon que je peux penser à le faire.

Si vous allez avec cette approche cependant, assurez-vous d'utiliser les modèle , et veiller à ce que la mise en œuvre interne (utilisation de HashMaps) est caché dans le code client. Assurez-vous également de vérifier avant d'écrire à la base de données que la taille de votre collection ne dépasse pas le nombre de colonnes disponibles.

Les avantages de cette approche:

  • Pas de changement à la base de données du tout
  • Les données sont actualisable
  • O / R est relativement simple

Les inconvénients:

  • Beaucoup de plomberie dans la couche DAO pour cartographier les types appropriés
  • Utilise les fonctionnalités expérimentales Hibernate qui peuvent changer dans l'avenir

Autres conseils

Personnellement, je pense que le design ressemble à ça casse première forme normale pour les bases de données relationnelles. Qu'advient-il si vous avez besoin C101 ou M101? Changer votre schéma à nouveau? Je pense qu'il est très intrusif.

Si vous ajoutez Mise en veille prolongée au mélange, il est encore pire. Ajout C101 ou M101 signifie devoir modifier vos objets Java, vos applications Hibernate, tout.

Si vous avez 1: relations m avec des tables C et M, vous seriez en mesure gérer les cas que je viens de citer en ajoutant des lignes supplémentaires. Vos objets Java contiennent Collection ou Collection . Vos applications Hibernate sont un à plusieurs qui ne changent pas.

Peut-être la raison pour laquelle vous ne voyez pas d'exemples d'Hibernate pour correspondre à votre cas, car il est une conception qui n'est pas recommandé.

Si vous devez, peut-être que vous devriez regarder Mise en veille prolongée Component Mapping .

MISE À JOUR: Le fait que ce legs est dûment noté. Mon point à mettre en place la première forme normale est autant pour les autres qui pourraient trouver cette question à l'avenir que pour la personne qui a posté la question. Je ne voudrais pas répondre à la question de telle manière qu'il a affirmé en silence cette conception comme « bon ».

Indiquant la cartographie des composants Hibernate est pertinente parce que connaître le nom de ce que vous cherchez peut être la clé lorsque vous recherchez. Mise en veille prolongée permet un modèle d'objet à grain plus fin que le modèle relationnel mappe. Vous êtes libre de modéliser un schéma dénormalisé (par exemple, les objets Nom et adresse dans le cadre d'un objet plus grande personne). C'est tout simplement le nom qu'ils donnent une telle technique. Il pourrait aider à trouver d'autres exemples.

Désolé si je suis malentendu votre problème ici, je ne sais pas beaucoup sur Hibernate. Mais ne pourriez-vous concaténer lors de la sélection de base de données pour obtenir quelque chose comme ce que vous voulez?

Comme:

SELECT whatever
     , C1||C2||C3||C4||...||C100 AS CDATA
     , M1||M2||M3||M4||...||M100 AS MDATA
FROM ...
WHERE ...

(Bien sûr, l'opérateur de concaténation diffère entre SGBDR.)

[EDIT] Je suggère d'utiliser un CompositeUserType. Voici un exemple . Il y a aussi un bon exemple à la page 228F dans le livre « Java Persistence Avec Mise en veille prolongée ».

Cela vous permet de gérer les nombreuses colonnes comme un seul objet en Java.

Le mappage ressemble à ceci:

@org.hibernate.annotations.Columns(columns = {
    @Column(name="C1"),
    @Column(name="C2"),
    @Column(name="C3"),
    ...
})
private List<Integer> c;

Hibernate chargera toutes les colonnes à la fois lors de la requête normale.

Dans votre cas, vous devez copier les valeurs int de la liste en un nombre fixe de colonnes dans nullSafeSet. Pseudocode:

for (int i=1; i<numColumns; i++)
    if (i < list.size())
        resultSet.setInt(index+i, list.get(i));
    else
        resultSet.setNull(index+i, Hibernate.INTEGER.sqlType());

Dans nullSafeGet vous devez créer une liste et arrêter d'ajouter des éléments lorsqu'une colonne est NULL. Pour plus de sécurité, je vous propose de créer votre propre implémentation de liste qui ne permet pas de se développer au-delà du nombre de colonnes (de ArrayList et hérite override ensureCapacity()).

[EDIT2] Si vous ne voulez pas taper toutes les annotations @Column, utilisez un générateur de code pour eux. Cela peut être aussi simple que le script que vous donnez un nom et un numéro et il imprime @Column (...) à System.out. Une fois le script a couru, il suffit de couper et coller les données dans la source.

La seule autre solution serait d'accéder à l'API interne Hibernate pour construire ces informations lors de l'exécution, mais que l'API est interne, donc beaucoup de choses est privé. Vous pouvez utiliser la réflexion Java et setAccessible(true) mais que le code ne survivra probablement pas la prochaine mise à jour de mise en veille prolongée.

Vous pouvez utiliser UserTypes pour mapper un nombre donné de colonnes à tout type que vous souhaitez. Cela pourrait être une collection si (par exemple) pour les collections sont toujours limitée en taille par un nombre connu d'éléments.

Il a été un certain temps (> 3 ans) depuis je Hibernate donc je suis assez rouillé, mais je me souviens qu'il soit très facile à faire; votre classe BespokeUserType est transmis le ResultSet hydrate votre objet de celui-ci.

Moi aussi je ne l'ai jamais utilisé Hibernate.

Je suggère d'écrire un petit programme dans un langage interprété (comme Python ) dans lequel vous pouvez exécuter une chaîne comme si elle était une commande. Vous pouvez construire une déclaration qui prend le travail fastidieux de faire ce que vous voulez faire manuellement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top