하드 코딩된 SQL 쿼리와 긴밀하게 결합된 데이터 액세스 코드는 데이터베이스를 스케일링하거나 전환하기 어렵게 만들 수 있으며 종종 반복되는 논리로 이어질 수 있습니다.
Copilot Chat에서는 데이터베이스 상호 작용을 추상화하고 코드를 모듈화하고 중복성을 줄이는 리포지토리 패턴이나 데이터 액세스 계층을 구현하는 것이 좋습니다. 또한 SQL 쿼리를 최적화된 버전으로 리팩터링하여 성능과 유지 관리 기능을 향상할 수 있습니다.
Note
이 문서에 설명된 응답은 예제입니다. Copilot Chat 응답은 비결정적이므로 여기에 표시된 응답과 다른 응답을 얻을 수 있습니다.
예제 시나리오
이 Python 코드는 SQLite 데이터베이스에 연결하고 사용자 레코드를 검색하고 사용자 데이터를 반환합니다. 그러나 데이터베이스 연결 논리를 추상화하지 못하고 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
예제 프롬프트 1
먼저 Copilot에게 코드를 개선하는 방법에 대한 일반적인 질문을 할 수 있습니다.
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.
예제 응답 1
Copilot는 코드를 개선하기 위해 다음과 같은 몇 가지 제안을 합니다.
- 데이터베이스 연결 세부 정보를 추상화합니다.
- 매개 변수가 있는 쿼리를 사용하여 SQL 삽입을 방지합니다.
- 컨텍스트 관리자를 사용하여 오류가 발생할 경우 데이터베이스 연결이 제대로 닫혀 있는지 확인합니다.
- 오류 처리 기능을 추가하세요.
예제 프롬프트 2
첫 번째 프롬프트에 대한 응답을 사용하여 보다 구체적인 프롬프트를 작성할 수 있습니다.
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.
예제 응답 2
Copilot는 코드를 각각 특정 용도로 별도의 파일로 분할하는 것이 좋습니다. 또한 사용자의 세부 정보를 반환하기 위한 예제 코드도 제공합니다.
제안된 변경 내용은 리포지토리 패턴을 구현하고 매개 변수가 있는 쿼리를 사용하여 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.")
수정된 코드는 다음과 같은 여러 가지 방법으로 원본에서 개선됩니다.
- 이제 코드는 기본 데이터 액세스 레이어를 구현합니다.
Database
클래스는 SQLite 데이터베이스에 대한 연결을 처리하고, 컨텍스트 관리자 프로토콜과__exit__
및__enter__
메서드를 구현합니다. 이렇게 하면 트랜잭션 커밋과 연결 닫기를 포함하여 데이터베이스 연결이 제대로 관리됩니다.UserRepository
클래스는 사용자 데이터에 액세스하기 위한 논리를 캡슐화합니다.- 쿼리 값은 SQL 삽입을 방지하기 위해 매개 변수화됩니다.
- 콘솔에 세부 정보가 인쇄되어 오류가 발생합니다.