DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Uncategorized»Erreur de calcul architectural et problème d’hibernation
    Uncategorized

    Erreur de calcul architectural et problème d’hibernation

    février 1, 2023
    Erreur de calcul architectural et problème d'hibernation
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    De nos jours, il est difficile de trouver un service qui fonctionne tout seul et qui ne communique pas avec d’autres services, en particulier les systèmes modernes construits sur une architecture de microservices. À cet égard, il est difficile d’obtenir des données de l’un ou l’autre service car toutes les données nécessaires au fonctionnement du service ne sont pas stockées dans une seule base de données et vous ne pouvez pas simplement faire une « jointure ». Je veux parler d’un de ces problèmes et de sa solution dans cet article.

    Description du cas

    Un grand nombre de projets utilisent Spring + Hibernate. Ce bundle donne un avantage en termes de vitesse de développement, réduisant la quantité de code et bla bla bla. Mais il y a aussi des inconvénients.

    Imaginons la situation suivante ; nous avons une entité « Document » qui contient des champs parmi lesquels il y a (Id, Title, Author_id). Et pour le moment, le tableau avec les données des auteurs est stocké dans la même base de données. Nous avons également d’autres services qui stockent toutes les entités avec un lien vers les auteurs. Comme vous l’avez peut-être deviné, les données des auteurs sont difficiles à tenir à jour avec cette approche. Ils doivent être stockés dans un service séparé qui les tient à jour.

    Service de documentation

    Un exemple de code Java simple lorsque les données sont stockées dans la même base de données :

    @Entity
    public class Author {
    
      @Id
      private UUID id;
    ...

    public class Document {
    
      @Id
      private Integer id;
      @Column(name = "title")
      private String title;
      @Column(name = "author_id")
      @ManyToOne
      private Author author;
      ...

    Nous devons donc modifier le champ auteur afin que les données soient remplies non pas à partir de la base de données de ce service mais à partir d’un autre service. Notre base de données ne contient que l’identifiant de l’auteur.

    Service Document et Service Utilisateur

    La chose la plus simple qui vient à l’esprit est de déclarer le champ auteur comme un UUID et, après avoir demandé cette entité, convertissez-la en un DocumentDto qui contiendra le champ auteur en tant qu’objet et l’enrichira à partir d’une autre source.

    Cette option convient lorsqu’il y a peu de références à ce champ dans le code et que vous utilisez DU REPOS.

    Dans notre cas, GraphQL est utilisé, il existe de nombreuses références à l’entité Document et nous n’avons pas besoin d’un DTO.

    La solution la plus courante consiste à utiliser un convertisseur.

    Exemple de code

    public class Author {
      private UUID id;
      private String firstname;
      private String lastname;
      ...

    Document en classe

    @Column(name = "author_id")
    @Convert(converter = AuthorConverter.class)
    private Author author;

    Convertisseur

    @Converter
    public class AuthorConverter implements AttributeConverter<Author, UUID> {
    
      @Override
      public UUID convertToDatabaseColumn(Author author) {
        return author.getId();
      }
    
      @Override
      public Author convertToEntityAttribute(UUID id) {
        Author author = new Author();
        author.setId(id);
        return author;
      }
    }

    C’est là que réside le principal problème si vous utilisez le type UUID comme auteur de l’identifiant.

    Lorsque vous essayez d’enregistrer ou de modifier l’entité de document dans la base de données à l’aide de la méthode d’enregistrement de JpaRepository, nous obtenons une exception.

    Lorsque vous utilisez Hibernate-core 5.4.29. Enfin, l’UUID est défini comme un type Varbinary lorsqu’il est converti et lève l’exception suivante :

    ERREUR : la colonne « author_id » est de type uuid mais l’expression est de type bytea.

    Capture d'écran du débogueur.

    Capture d’écran du débogueur.

    Lorsque vous utilisez Hibernate-core 5.6.14. Enfin, l’UUID est défini comme un type Varchar lorsqu’il est converti et lève l’exception suivante :

    ERREUR : la colonne « author_id » est de type uuid mais l’expression est de type caractère variable.

    Après une recherche sur Google, je suis arrivé à la conclusion que beaucoup changent simplement le type d’UUID en String et vivent avec cette solution. C’est clairement une béquille et je n’aime pas ça.

    La deuxième béquille que j’ai trouvé dans le code de mes collègues est d’ajouter un champ de plus à l’entité Document (oh mes yeux)comme indiqué ci-dessous:

    Exemple de code

    @Column(name = "author_id", updatable = false, insertable = false)
    @Convert(converter = AuthorConverter.class)
    private Author author;
    
    @Column(name = "author_id")
    private UUID authorId;

    Cette méthode peut dérouter les autres développeurs car il n’est pas immédiatement clair quel champ l’auteur doit remplir lors de l’enregistrement de l’entité.

    Dans les deux cas, l’enregistrement via la méthode d’enregistrement fonctionnera pour vous.

    Une façon de contourner ce problème consiste à enregistrer et à modifier l’entité avec des requêtes natives. Dès que cela m’est venu à l’esprit, je l’ai vérifié et cela fonctionne. Cependant, bien que j’aime les requêtes natives, je n’aime pas non plus cette option car si vous avez de nombreux champs dans l’entité, l’appel de la méthode save or change avec tous ces champs aura l’air terrible.

    Exemple de code

    @Query(nativeQuery = true, value = "INSERT INTO public.document (title, author_id)"
        + " VALUES (?1, ?2)")
    void insert(String title, UUID authorId);

    La quatrième béquille fonctionnera pour postgres. Étant donné que cette base de données ne prend pas en charge le type Varbinary, vous pouvez modifier le type de ce champ dans la base de données en Bytea. Je n’ai pas essayé cette solution avec Oracle DB.

    De toutes les béquilles ci-dessus, je choisirais très probablement la troisième (requêtes natives), mais je n’aime pas le code avec des béquilles et j’ai continué à penser à résoudre le problème.

    Après avoir un peu débogué le code, j’ai décidé d’aller dans l’autre sens et de ne pas utiliser le convertisseur. Vous pouvez vous passer d’un convertisseur en faisant de l’auteur une entité intégrée (@Embedded), mais comme nous n’utilisons que l’identifiant de l’auteur pour enregistrer dans notre base de données, le reste des champs doit être déplacé vers la superclasse. Voici un exemple de code de test.

    Exemple de code

    ...
    @Entity
    public class Document {
    
      @Id
      private Integer id;
    
      @Column(name = "title")
      private String title;
    
      @Embedded
      @AttributeOverrides(@AttributeOverride(name = "id", column = @Column(name = "author_id")))
      private Author author;
    }

    ...
    @Embeddable
    public class Author extends AuthorFields {
    
      private UUID id;
    
    }
    ...
    public class AuthorFields {
    
      private String firstname;
      private String lastname;
    }

    Cette méthode fonctionne très bien ; pas besoin de changer le type de données dans la base de données ou de faire des requêtes natives pour enregistrer les données. Cependant, c’est là que je me suis arrêté.

    Conclusion

    Dans cet article, j’ai essayé de décrire le problème existant et les moyens de le résoudre sans texte inutile.

    Encore une fois, j’étais convaincu qu’il ne fallait pas se précipiter vers la première solution rencontrée sur StackOverflow, même si toutes les solutions à ce problème que j’y ai trouvées consistaient à utiliser String.

    Peut-être que cet article aidera quelqu’un et lui facilitera la vie)

    Merci pour votre attention!

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.