Skip to main content

Refactorisation des couches d’accĂšs aux donnĂ©es

Copilot Chat peut vous suggĂ©rer des moyens de dissocier votre code d’accĂšs aux donnĂ©es de votre logique mĂ©tier, rendant ainsi votre application plus facile Ă  maintenir et Ă  faire Ă©voluer.

Les requĂȘtes SQL codĂ©es en dur et le code d’accĂšs aux donnĂ©es Ă©troitement couplĂ©s peuvent rendre difficile la mise Ă  l’échelle ou le changement de bases de donnĂ©es, et ils mĂšnent souvent Ă  une logique rĂ©pĂ©tĂ©e.

Copilot Chat peut recommander la mise en Ɠuvre d’un modĂšle de rĂ©fĂ©rentiel ou d’une couche d’accĂšs aux donnĂ©es qui abstrait les interactions avec la base de donnĂ©es, rendant ainsi le code plus modulaire et rĂ©duisant la redondance. Il peut Ă©galement aider Ă  remanier les requĂȘtes SQL pour en faire des versions optimisĂ©es, amĂ©liorant ainsi les performances et la maintenabilitĂ©.

Remarque

Les réponses décrites dans cet article sont des exemples. Les réponses Copilot Chat ne sont pas déterministes, vous pouvez donc obtenir des réponses différentes de celles affichées ici.

Exemple de scénario

Ce code Python se connecte Ă  une base de donnĂ©es SQLite, rĂ©cupĂšre un enregistrement utilisateur et retourne les donnĂ©es utilisateur. Toutefois, elle ne parvient pas Ă  abstraction de la logique de connexion de base de donnĂ©es et utilise une requĂȘte codĂ©e en dur vulnĂ©rable Ă  l’injection SQL.

import sqlite3

def get_user_by_id(user_id):
    conn = sqlite3.connect('database.db')
    cursor = conn.cursor()
    cursor.execute(f"SELECT display_name FROM users WHERE id = {user_id}")
    user = cursor.fetchone()
    conn.close()
    return user

Exemple d'invite 1

Vous pouvez commencer par poser Copilot une question générale sur la maniÚre d'améliorer le code.

How can I improve this code to make it safe and easier to update and expand? List possible improvements but don't show revised code.

Exemple de réponse 1

Copilot fait plusieurs suggestions pour améliorer le code :

  • Abstrait les dĂ©tails de la connexion Ă  la base de donnĂ©es.
  • Utilisez des requĂȘtes paramĂ©trables pour empĂȘcher l’injection SQL.
  • Utilisez un gestionnaire de contexte pour vous assurer que la connexion de base de donnĂ©es est correctement fermĂ©e si une erreur se produit.
  • Ajouter la gestion des erreurs.

Exemple d'invite 2

Vous pouvez utiliser la réponse à votre premiÚre invite pour écrire une invite plus spécifique.

Rewrite this code to make it more scalable and easier to maintain. Use a context manager. Avoid hardcoded SQL queries and tightly coupled data access code. Instead, use a repository pattern to abstract database interactions and make the code more modular and reusable. Where possible optimize the code to improve performance. Include error trapping, and make sure the code is not vulnerable to SQL injection.

Exemple de réponse 2

Copilot suggĂšre de diviser le code en plusieurs fichiers distincts, chacun ayant un objectif spĂ©cifique. Il fournit Ă©galement un exemple de code pour renvoyer les dĂ©tails d’un utilisateur.

Les modifications suggĂ©rĂ©es implĂ©mentent un modĂšle de rĂ©fĂ©rentiel et utilisent des requĂȘtes paramĂ©trables pour Ă©viter l’injection SQL.

# database.py
import sqlite3

class Database:
    def __init__(self, db_path):
        self.db_path = db_path

    def __enter__(self):
        self.conn = sqlite3.connect(self.db_path)
        self.cursor = self.conn.cursor()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type or exc_val or exc_tb:
            self.conn.rollback()
        else:
            self.conn.commit()
        self.conn.close()

# user_repository.py
class UserRepository:
    def __init__(self, db):
        self.db = db

    def get_user_by_id(self, user_id):
        try:
            self.db.cursor.execute("SELECT display_name FROM users WHERE id = ?", (user_id,))
            user = self.db.cursor.fetchone()
            return user
        except sqlite3.Error as e:
            print(f"An error occurred: {e}")
            return None

# main.py
from database import Database
from user_repository import UserRepository

def get_user_by_id(user_id):
    with Database('database.db') as db:
        user_repo = UserRepository(db)
        return user_repo.get_user_by_id(user_id)

# Example usage
if __name__ == "__main__":
    user = get_user_by_id(1)
    if user:
        print(user)
    else:
        print("User not found or an error occurred.")

Le code rĂ©visĂ© amĂ©liore l’original de plusieurs façons :

  • Le code implĂ©mente dĂ©sormais une couche d’accĂšs aux donnĂ©es de base.
  • La classe Database gĂšre la connexion Ă  la base de donnĂ©es SQLite, implĂ©mentant le protocole de gestionnaire de contexte avec les mĂ©thodes __enter__ et __exit__ . Cela garantit que la connexion de base de donnĂ©es est correctement gĂ©rĂ©e, notamment la validation des transactions et la fermeture de la connexion.
  • La classe UserRepository encapsule la logique d’accĂšs aux donnĂ©es utilisateur.
  • Les valeurs des requĂȘtes sont paramĂ©trĂ©es pour empĂȘcher l’injection SQL.
  • Les erreurs sont interceptĂ©es, avec des dĂ©tails imprimĂ©s sur la console.

Pour aller plus loin