Skip to main content

Umgestalten von Datenzugriffsschichten

Copilot Chat kann Möglichkeiten vorschlagen, den Datenzugriffscode von deiner Geschäftslogik zu entkoppeln, wodurch eine Anwendung einfacher verwaltet und skaliert werden kann.

Durch hartcodierte SQL-Abfragen und einen eng gekoppelten Datenzugriffscode können sich Skalierung und Wechsel von Datenbanken als schwierig erweisen. Außerdem kann dabei wiederholte Logik entstehen.

Copilot Chat kann die Implementierung eines Repositorymusters oder einer Datenzugriffsschicht empfehlen, die Datenbankinteraktionen abstrahiert. Dadurch wird der Code modularer gestaltet und Redundanz reduziert. Copilot Chat kann außerdem dazu beitragen, SQL-Abfragen in optimierte Versionen umzugestalten, was zu einer Verbesserung von Leistung und Wartbarkeit zu führt.

Note

Bei den in diesem Artikel beschriebenen Antworten handelt es sich um Beispiele. Da die Copilot Chat-Antworten nicht deterministisch sind, erhältst du möglicherweise andere Antworten als die hier dargestellten.

Beispielszenario

Dieser Python-Code stellt eine Verbindung mit einer SQLite-Datenbank her, ruft einen Benutzerdatensatz ab und gibt die Benutzerdaten zurück. Der Code kann die Datenbankverbindungslogik jedoch nicht abstrahieren und verwendet eine hartcodierte Abfrage, die anfällig für die Einschleusung von SQL-Befehlen 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 zur Verbesserung des Codes stellen.

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 stellt mehrere Vorschläge zur Verbesserung des Codes bereit:

  • Abstrahieren der Datenbankverbindungsdetails
  • Verwenden parametrisierter Abfragen, um die Einschleusung von SQL-Befehlen zu verhindern
  • Verwenden eines Kontext-Managers, damit die Datenbankverbindung beim Auftreten eines Fehlers ordnungsgemäß geschlossen wird
  • Hinzufügen einer Fehlerbehandlung

Beispielprompt 2

Du kannst die Antwort auf deinen ersten Prompt verwenden, um einen spezifischeren Prompt zu formulieren.

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 separate Dateien aufzuteilen, die jeweils einen bestimmten Zweck erfüllen. Außerdem wird Beispielcode bereitgestellt, der die Details eines Benutzers zurückgibt.

Die vorgeschlagenen Änderungen implementieren ein Repositorymuster und verwenden parametrisierte Abfragen, um die Einschleusung von SQL-Befehlen 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.")

Durch den überarbeiteten Code wird das Original auf verschiedene Arten verbessert:

  • Der Code implementiert nun eine grundlegende Datenzugriffsschicht.
  • Die Database-Klasse verarbeitet die Verbindung mit der SQLite-Datenbank und implementiert das Protokoll des Kontext-Managers mit den Methoden __enter__ und __exit__. Dadurch wird sichergestellt, dass die Datenbankverbindung ordnungsgemäß verwaltet wird, einschließlich des Commits von Transaktionen und des Schließens der Verbindung.
  • Die UserRepository-Klasse kapselt die Logik für den Zugriff auf Benutzerdaten.
  • Werte für die Abfragen werden parametrisiert, um die Einschleusung von SQL-Befehlen zu verhindern.
  • Fehler werden abgefangen, und Details werden in der Konsole ausgegeben.

Weitere Informationen