{"meta":{"title":"Рефакторинг слоёв access к данным","intro":"Копилот Чат может предложить способы отделения ваших данных access кода от бизнес-логики, что облегчает обслуживание и масштабирование приложения.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ru/copilot","title":"GitHub Copilot"},{"href":"/ru/copilot/tutorials","title":"Учебники"},{"href":"/ru/copilot/tutorials/copilot-chat-cookbook","title":"Кулинарная книга чата GitHub Copilot"},{"href":"/ru/copilot/tutorials/copilot-chat-cookbook/refactor-code","title":"Рефакторинг кода"},{"href":"/ru/copilot/tutorials/copilot-chat-cookbook/refactor-code/refactor-data-access-layers","title":"Refactoring data access layers"}],"documentType":"article"},"body":"# Рефакторинг слоёв access к данным\n\nКопилот Чат может предложить способы отделения ваших данных access кода от бизнес-логики, что облегчает обслуживание и масштабирование приложения.\n\nЖёстко закодированные SQL-запросы и тесно связанный код access к данным могут затруднять масштабирование или переключение баз данных и часто приводят к повторяющейся логике.\n\nКопилот Чат может рекомендовать реализовать шаблон репозитория или слой access данных, который абстрагирует взаимодействия с базой данных, делая код более модульным и снижая избыточность. Кроме того, он может помочь рефакторингу запросов SQL в оптимизированные версии, повысить производительность и удобство обслуживания.\n\n> \\[!NOTE] Ответы, описанные в этой статье, являются примерами. Ответы Копилот Чат являются недетерминированными, поэтому вы можете получить различные ответы, показанные здесь.\n\n## Пример сценария\n\nЭтот код Python подключается к базе данных SQLite, извлекает запись пользователя и возвращает данные пользователя. Однако она не может абстрагировать логику подключения к базе данных и использует жестко закодированный запрос, который уязвим для внедрения SQL.\n\n```python id=database-connection\nimport sqlite3\n\ndef get_user_by_id(user_id):\n    conn = sqlite3.connect('database.db')\n    cursor = conn.cursor()\n    cursor.execute(f\"SELECT display_name FROM users WHERE id = {user_id}\")\n    user = cursor.fetchone()\n    conn.close()\n    return user\n```\n\n## Пример запроса 1\n\nДля начала можно задать Copilot общий вопрос о том, как улучшить код.\n\n```copilot copy prompt ref=database-connection\nHow can I improve this code to make it safe and easier to update and expand? List possible improvements but don't show revised code.\n```\n\n## Пример ответа 1\n\nCopilot предлагает несколько предложений по улучшению кода:\n\n* Абстрагирование сведений о подключении к базе данных.\n* Используйте параметризованные запросы, чтобы предотвратить внедрение SQL.\n* Используйте диспетчер контекстов, чтобы убедиться, что подключение к базе данных правильно закрыто при возникновении ошибки.\n* Добавьте обработку ошибок.\n\n## Пример запроса 2\n\nВы можете использовать ответ на первый запрос, чтобы написать более конкретный запрос.\n\n```copilot copy prompt ref=database-connection\nRewrite 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.\n```\n\n## Пример ответа 2\n\nCopilot предлагает разделить код на отдельные файлы, каждый из которых имеет определенную цель. Он также содержит пример кода для возврата сведений о пользователе.\n\nПредлагаемые изменения реализуют шаблон репозитория и используют параметризованные запросы, чтобы избежать внедрения SQL.\n\n```python\n# database.py\nimport sqlite3\n\nclass Database:\n    def __init__(self, db_path):\n        self.db_path = db_path\n\n    def __enter__(self):\n        self.conn = sqlite3.connect(self.db_path)\n        self.cursor = self.conn.cursor()\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        if exc_type or exc_val or exc_tb:\n            self.conn.rollback()\n        else:\n            self.conn.commit()\n        self.conn.close()\n\n# user_repository.py\nclass UserRepository:\n    def __init__(self, db):\n        self.db = db\n\n    def get_user_by_id(self, user_id):\n        try:\n            self.db.cursor.execute(\"SELECT display_name FROM users WHERE id = ?\", (user_id,))\n            user = self.db.cursor.fetchone()\n            return user\n        except sqlite3.Error as e:\n            print(f\"An error occurred: {e}\")\n            return None\n\n# main.py\nfrom database import Database\nfrom user_repository import UserRepository\n\ndef get_user_by_id(user_id):\n    with Database('database.db') as db:\n        user_repo = UserRepository(db)\n        return user_repo.get_user_by_id(user_id)\n\n# Example usage\nif __name__ == \"__main__\":\n    user = get_user_by_id(1)\n    if user:\n        print(user)\n    else:\n        print(\"User not found or an error occurred.\")\n```\n\nИзмененный код улучшает исходный код несколькими способами:\n\n* Теперь код реализует базовый слой data access.\n* Класс `Database` обрабатывает подключение к базе данных SQLite, реализуя протокол диспетчера контекстов с `__enter__` помощью методов и `__exit__` методов. Это гарантирует правильное управление подключением к базе данных, включая фиксацию транзакций и закрытие подключения.\n* Класс `UserRepository` инкапсулирует логику доступа к данным пользователя.\n* Значения запросов параметризованы, чтобы предотвратить внедрение SQL.\n* Ошибки перехватываются с подробными сведениями, напечатанными в консоли.\n\n## Дополнительные материалы\n\n* [Инженерия подсказок для GitHub Copilot Chat](/ru/copilot/using-github-copilot/prompt-engineering-for-github-copilot)\n* [Лучшие практики использования GitHub Copilot](/ru/copilot/using-github-copilot/best-practices-for-using-github-copilot)"}