Hart kodierte SQL-Abfragen und fest eingebundener Code für den Datenzugriff können die Skalierung oder den Wechsel von Datenbanken erschweren und führen oft zu wiederholter Logik.
Copilot-Chat kann empfehlen, ein Repository-Muster oder eine Datenzugriffsschicht zu implementieren, die Datenbankinteraktionen abstrahiert, den Code modularer macht und Redundanzen reduziert. Es kann auch dabei helfen, SQL Abfragen in optimierte Versionen zu refactorieren und so die Leistung und Wartbarkeit zu verbessern.
Hinweis
Die in diesem Artikel beschriebenen Antworten sind Beispiele. Da die Copilot-Chat-Antworten nicht deterministisch sind, erhältst du möglicherweise andere Antworten als die hier dargestellten.
Beispielszenario
Dieser Python Code verbindet sich mit einer SQLite Datenbank, ruft einen Datensatz eines Benutzers ab und gibt die Benutzerdaten zurück. Allerdings wird die Logik der Datenbankverbindung nicht abstrahiert und eine fest kodierte Abfrage verwendet, die für SQL-Injection anfällig ist.
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
Beispielprompt 1
Du kannst damit beginnen, Copilot eine allgemeine Frage zu stellen, wie du den Code verbessern kannst.
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.
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
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.
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.
Beispielantwort 1
Copilot macht mehrere Vorschläge zur Verbesserung des Codes:
- Abstrahiere die Details der Datenbankverbindung.
- Verwende parametrisierte Abfragen, um SQL-Injection zu verhindern.
- Verwende einen Kontext-Manager, um sicherzustellen, dass die Datenbankverbindung im Fehlerfall ordnungsgemäß abgeschlossen wird.
- Füge eine Fehlerbehandlung hinzu.
Beispielprompt 2
Du kannst die Antwort auf deinen ersten Prompt verwenden, um einen spezifischeren Prompt zu schreiben.
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.
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
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.
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.
Beispielantwort 2
Copilot schlägt vor, den Code in verschiedene Dateien aufzuteilen, die jeweils einen bestimmten Zweck erfüllen. Außerdem gibt es einen Beispielcode für die Rückgabe der Daten eines Benutzers.
Die vorgeschlagenen Änderungen implementieren ein Repository-Muster und verwenden parametrisierte Abfragen, um SQL-Injection zu vermeiden.
# 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.")
Der überarbeitete Code ist in mehrfacher Hinsicht besser als das Original:
- Der Code implementiert jetzt eine Basiszugriffsschicht.
- Die Klasse
Databasehandhabt die Verbindung zur SQLite-Datenbank und implementiert das Context Manager-Protokoll mit den Methoden__enter__und__exit__. Dadurch wird sichergestellt, dass die Datenbankverbindung ordnungsgemäß verwaltet wird, einschließlich des Commitings von Transaktionen und des Schließens der Verbindung. - Die Klasse
UserRepositorykapselt die Logik für den Zugriff auf die Benutzerdaten. - Die Werte für die Abfragen sind parametrisiert, um SQL-Injection zu verhindern.
- Fehler werden abgefangen und die Details auf der Konsole ausgegeben.