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.