Как связать базу данных с приложением

Обновлено: 24.04.2024

Приветствую всех дроидеров в эти непростые для нас времена.
Честно говоря, заколебала эта шумиха о патентах, войнах и т.д., но в данной статье речь пойдет не об этом.
Я не собирался писать статью на данную тему, так как везде всего полно о работе с базой данных в Android и вроде бы все просто, но уж очень надоело получать репорты об ошибках, ошибках специфичных и связанных с БД.
Поэтому, я рассматрю пару моментов с которыми я столкнулся на практике, чтобы предостеречь людей, которым только предстоит с этим разбираться, а дальше жду ваших комментариев на тему решения указанных проблем после чего внесу изменения в пост и мы сделаем отличный туториал, который будет образцом работы с SQLite в Android не только для начинающих, но и для тех, кто уже знаком с основами и написал простые приложения.

Способы работы с БД

Примерно так. Более полный вариант класса и других составляющих можно посмотреть по ссылке внизу статьи.
Дополнительно можно переопределить методы onOpen(), getReadableDatabase()/getWritableDatаbase(), но обычно хватает того, что выше и методов выборки данных.
Далее, экземпляр этого класса создаем в нашем приложении при его запуске и выполняем запросы, то бишь проблемная часть пройдена. Почему она проблемная? Потому что, когда пользователь качает приложения с маркета, то не задумывается о вашей базе данных и может произойти что угодно. Скажем сеть пропала или процесс другой запустился, или вы написали уязвимый к ошибкам код.

Кстати, есть еще один момент, на который стоит обратить внимание. Переменную экземпляра нашего класса можно создать и хранить в объекте Application и обращаться по мере необходимости, но нужно не забывать вызывать метод close(), так как постоянный коннект к базе — это тяжелый ресурс. Кроме того могут быть коллизии при работе с базой из нескольких потоков.
Но есть и другой способ, например, создавать наш объект по мере необходимости обращения к БД. Думаю это вопрос предпочтения, но который также необходимо обсудить.

Вот они:
1) В методе createDataBase() строка:
SQLiteDatabase dbRead = getReadableDatabase();
и далее код… содержит crash приложения на НТС Desire, потому что получаем БД для чтения(она создается), но не закрывается.
Добавляем строкой ниже dbRead.close() и фикс готов, но момент спорный.
Вот что говорит дока на тему метода getReadableDatabase():
Create and/or open a database. This will be the same object returned by getWritableDatabase() unless some problem, such as a full disk, requires the database to be opened read-only. In that case, a read-only database object will be returned. If the problem is fixed, a future call to getWritableDatabase() may succeed, in which case the read-only database object will be closed and the read/write object will be returned in the future.
Like getWritableDatabase(), this method may take a long time to return, so you should not call it from the application main thread, including from ContentProvider.onCreate().

И так. Данный метод не стоит вызывать в главном потоке приложения. В остальном все понятно.
2) Ошибка: No such table android_metadata. Автор поста выкрутился, создав данную таблицу заранее в БД. Не знаю на сколько это правильный способ, но данная таблица создается в каждой sqlite-бд системой и содержит текущую локаль.
3) Ошибка: Unable to open database file. Здесь много мнений, разных мнений, которые Вы можете прочесть по ссылкам ниже.

Возможно, что проблемы связаны с тем, что один поток блокирует БД и второй не может к ней обратиться, возможно проблема в правах доступа к приложению(было замечено, что чаще проблемы с БД проявляются на телефонах марки НТС именно на тех моделях, которые нельзя рутануть, хотя не только на них, например на планшетах Асер), но как бы то ни было проблемы эти есть.
Я склоняюсь к варианту, что проблема в потоках, не зря ведь нам не рекомендуют вызывать методы создания базы в главном потоке.

Возможно выходом из этого будет следующее решение(рассматривается вариант №2). Используя первый вариант работы с базой, наполнить ее данными после создания, например:

Данный подход еще нужно проверить на практике, но так как этот пост нацелен на выработку верного коллективного решения по данной тематике, то комментарии и пробы на даннную тему только приветствуются.
Мораль истории такова: если вы нашли какой-то хороший кусок кода для вашего решения, то проверьте его, не поленитесь, прежде чем копипастить в свой проект.

Вцелом, данный пост показывает(касательно способа №2) как делать не надо, но и также содержит пару любопытных мыслей.
Метод getReadableDatabase() можно переопределить например так:

И класс приложения:

Отмечу, что данный класс используется только для демонстрации и проверки того, что произойдет при вызове методов getReadableDatabase()/getWritableDatabase() и создании базы. В реальных проектах код нужно адаптировать.
Кроме того в базе появилась табличка android_metadata(без моего участия), поэтому указанная выше ошибка решена.
Надеюсь кому-то пригодится.

Любопытные дополнения №1(от хабраюзера Kalobok)

Я пока совсем отказался от SQLiteOpenHelper — оказалось, что в нем невозможно создать базу на SD карте. Теоретически, то, что он возвращает, должно использоваться как путь к базе. На практике SQLiteOpenHelper иногда использует его, а иногда обходит стороной — зависит от того, открываем ли мы базу на чтение или запись, существует ли она уже и т.д. SQLiteOpenHelper.getWritableDatabase вызывает Context.openOrCreateDatabase, который, в свою очередь, использует Context.validateFilePath, чтобы получить полный путь к файлу. Там используется приватный метод Context.getDatabasesDir, переопределить который нельзя — приехали. База будет создана в стандартной директории.

можно проверить подключение к базе данных или службе, а также изучить содержимое базы данных и схемы с помощью обозреватель сервера, Cloud Explorer или SQL Server обозреватель объектов. Функциональные возможности этих окон перекрываются в некоторой степени. Основные отличия:

установите это окно вручную в качестве расширения Visual Studio из Visual Studio Marketplace. Предоставляет специализированные функциональные возможности для изучения и подключения к службам Azure.

Обозреватель объектов SQL Server

вы можете проверить подключение к базе данных или службе, а также изучить содержимое базы данных и схемы с помощью обозреватель сервера или SQL Server обозреватель объектов. Функциональные возможности этих окон перекрываются в некоторой степени. Основные отличия:

Обозреватель объектов SQL Server

Добавление подключения в обозреватель сервера

Чтобы создать подключение к базе данных, щелкните значок Добавить подключение в Обозреватель сервера или щелкните правой кнопкой мыши Обозреватель сервера в узле подключения к данным и выберите команду Добавить подключение. отсюда можно также подключиться к базе данных на другом сервере, SharePointной службе или службе Azure.

снимок экрана: обозреватель сервера Подключение значок базы данных.

Откроется диалоговое окно Добавление соединения . здесь мы указали имя экземпляра SQL Server LocalDB, (localdb)\MSSqlLocalDB который обычно устанавливается вместе с Visual Studio.

Снимок экрана: диалоговое окно

Снимок экрана: диалоговое окно

Изменение поставщика

если вы используете Visual Studio 2022 для подключения к поставщикам данных OLEDB или ODBC, необходимо помнить, что Visual Studio 2022 теперь является 64-битным процессом.

это означает, что некоторые средства работы с данными в Visual Studio не смогут подключаться к базам данных OLEDB или ODBC с помощью 32-разрядных поставщиков данных. Сюда входит поставщик данных Microsoft Access 32-bit OLEDB, а также другие сторонние поставщики 32-bit.

если необходимо поддерживать 32-разрядные приложения, подключающиеся к OLEDB или ODBC, вы по-прежнему сможете создавать и запускать приложение с Visual Studio 2022. тем не менее, если необходимо использовать какие-либо инструменты Visual Studio данных, такие как обозреватель сервера, мастер источников данных или конструктор наборов данных, необходимо использовать более раннюю версию Visual Studio, которая все еще является 32-битным процессом. последняя версия Visual Studio, которая была 32-разрядным процессом, была Visual Studio 2019.

Если вы планируете преобразовать проект в 64-разрядный процесс, вам потребуется обновить подключения к данным OLEDB и ODBC, чтобы использовать 64-разрядные поставщики данных.

если приложение использует базы данных Microsoft Access и может преобразовать проект в 64-разрядный, рекомендуется использовать 64-разрядный ядро СУБД Microsoft access, также называемый модулем подключения Access (ACE). Дополнительные сведения см. в разделе поставщик OLE DB для Jet и драйвер ODBC — 32-разрядные версии .

Если вы используете сторонний поставщик данных, мы рекомендуем подключиться к поставщику, чтобы узнать, предлагают ли они 64-разрядный поставщик перед преобразованием проекта в 64-разрядный.

Снимок экрана, показывающий, как изменить поставщик данных ADO.NET.

Снимок экрана, показывающий, как изменить поставщик данных ADO.NET.

Проверка подключения

После выбора источника данных нажмите кнопку проверить соединение. Если это не удается, вам потребуется устранить неполадки, используя документацию поставщика.

если тест выполнен, можно приступать к созданию источника данных, который является Visual Studio термином, который на самом деле означает модель данных , основанную на базовой базе данных или службе.

Подключение с помощью SQL Server обозреватель объектов

чтобы открыть диалоговое окно подключения из SQL Server обозреватель объектов, нажмите кнопку панели инструментов добавить SQL Server.

Откроется диалоговое окно подключения. выберите локальный, сетевой или Azure SQL сервер, выберите базу данных, укажите учетные данные и выберите Подключение.

снимок экрана Подключение диалогового окна SQL Server обозреватель объектов.

Если необходимо задать другие параметры в строке подключения, можно использовать ссылку Дополнительно , в которой будут выведены все параметры.

Снимок экрана, показывающий дополнительные параметры.

после завершения настройки подключения сервер и база данных отображаются в окне SQL Server обозреватель объектов.

Отсюда можно просматривать базу данных, создавать и выполнять запросы, изменять данные, хранимые процедуры и функции, а также выполнять другие действия непосредственно в Visual Studio.

Следующие шаги

В этой статье демонстрируется простой способ быстрого получения данных из базы данных. Если приложению необходимо изменить данные с помощью нетривиальных способов и обновить базу данных, следует рассмотреть возможность использования Entity Framework и привязки данных для автоматической синхронизации элементов управления пользовательского интерфейса с изменениями в базовых данных.

С целью упрощения код не включает обработку исключений для выполнения в рабочей среде.

Предварительные требования

Для создания приложения вам потребуются следующие компоненты.

SQL Server Express LocalDB. если у вас нет SQL Server Express LocalDB, его можно установить на странице загрузки SQL Server.

Настройка образца базы данных

Создайте образец базы данных, выполнив следующие действия.

в Visual Studio откройте окно обозреватель сервера .

щелкните правой кнопкой мыши подключения к данным и выберите команду создать новую базу данных SQL Server.

В текстовом поле имя сервера введите (LocalDB) \mssqllocaldb.

В текстовом поле имя новой базы данных введите Sales, а затем нажмите кнопку ОК.

Пустая база данных Sales создается и добавляется в узел подключения к данным в обозреватель сервера.

Щелкните правой кнопкой мыши подключение к данным о продажах и выберите создать запрос.

Откроется окно редактора запросов.

вставьте скрипт T-SQL в редактор запросов, а затем нажмите кнопку выполнить .

По истечении короткого времени выполнение запроса завершается и создаются объекты базы данных. База данных содержит две таблицы: Customer и Orders. Эти таблицы изначально не содержат данных, но их можно добавить при запуске создаваемого приложения. База данных также содержит четыре простые хранимые процедуры.

Создание форм и добавление элементов управления

Создайте проект для приложения Windows Forms и назовите его SimpleDataApp.

Visual Studio создает проект и несколько файлов, включая пустую форму Windows Forms с именем Form1.

Добавьте две формы Windows Forms в проект, чтобы он включал три формы, и назначьте им следующие имена:

Навигация

NewCustomer

FillOrCancel

Для каждой формы добавьте текстовые поля, кнопки и другие элементы управления, которые отображаются на рисунках ниже. Для каждого элемента управления задайте свойства, указанные в таблицах.

Элементы управления "группа" и "надпись" обеспечивают большую ясность, но не используются в коде.

Форма навигации

Диалоговое окно

Форма NewCustomer

Добавление нового заказчика и размещение заказа

Форма FillOrCancel

заполнение или отмена заказов

Сохранение строки подключения

Когда приложение пытается открыть подключение к базе данных, оно должно иметь доступ к строке подключения. Чтобы не вводить строку вручную в каждой форме, сохраните строку в файле App.config в проекте и создайте метод, возвращающий строку при вызове метода из любой формы в приложении.

Строку подключения можно найти, щелкнув правой кнопкой мыши подключение данных о продажах в Обозреватель сервера и выбрав Свойства. Найдите свойство ConnectionString , а затем с помощью клавиш CTRL + A, CTRL + C выберите и скопируйте строку в буфер обмена.

В столбце имя введите connString .

В списке тип выберите (строка подключения).

В списке область выберите приложение.

В столбце значение введите строку подключения (без кавычек), а затем сохраните изменения.

снимок экрана со строкой подключения в Параметры. Settings

В реальных приложениях строку подключения следует хранить безопасно, как описано в разделе строки подключения и файлы конфигурации.

Написание кода для форм

Этот раздел содержит краткие обзоры того, что делает каждая форма. Он также предоставляет код, определяющий базовую логику при нажатии кнопки на форме.

Форма навигации

Форма навигации открывается при запуске приложения. Кнопка Добавить учетную запись открывает форму NewCustomer. Кнопка Выполнение или отмена заказов открывает форму FillOrCancel. Кнопка Выход закрывает приложение.

Преобразование формы навигации в начальную форму

если вы используете Visual Basic, в обозреватель решений откройте окно свойства , перейдите на вкладку приложение и выберите симпледатаапп. Navigation в списке начальных форм .

Создание автоматически создаваемых обработчиков событий

Дважды щелкните три кнопки в форме навигации, чтобы создать пустые методы обработчика событий. При двойном щелчке кнопки также добавляется автоматически созданный код в файл кода конструктора, который позволяет нажать кнопку для вызова события.

Если пропустить действие двойного щелчка в конструкторе и просто скопировать код и вставить его в файлы кода, не забудьте присвоить обработчику событий правильный метод. Это можно сделать в окне Свойства . Перейдите на вкладку события (воспользуйтесь кнопкой на панели инструментов с молнией) и найдите обработчик щелчка .

Добавление кода для логики формы навигации

На странице кода для формы навигации заполните основные тексты методов для трех обработчиков событий нажатия кнопки, как показано в следующем коде.

Форма NewCustomer

если ввести имя клиента, а затем нажать кнопку создать учетную запись , форма NewCustomer создает учетную запись клиента, а SQL Server возвращает значение идентификатора в качестве нового идентификатора клиента. Затем можно разместить заказ для новой учетной записи, указав сумму и дату заказа и нажав кнопку поместить порядок .

Создание автоматически создаваемых обработчиков событий

Создайте пустой обработчик событий щелчка для каждой кнопки в форме NewCustomer, дважды щелкнув каждую из четырех кнопок. При двойном щелчке кнопки также добавляется автоматически созданный код в файл кода конструктора, который позволяет нажать кнопку для вызова события.

Добавление кода для логики формы NewCustomer

Чтобы завершить логику формы NewCustomer, выполните следующие действия.

System.Data.SqlClient Перенесите пространство имен в область, чтобы не указывать полные имена его членов.

Добавьте в класс некоторые переменные и вспомогательные методы, как показано в следующем коде.

Заполните основные тексты методов для четырех обработчиков событий нажатия кнопки, как показано в следующем коде.

Форма FillOrCancel

Форма Филлорканцел запускает запрос для возврата заказа при вводе идентификатора заказа и нажатия кнопки найти заказ . Возвращенная строка отображается в сетке данных только для чтения. Можно пометить заказ как отмененный (X), если нажать кнопку отменить заказ или пометить заказ как заполненный (F), если нажать кнопку заполнить заказ . Если нажать кнопку найти порядок еще раз, появится обновленная строка.

Создание автоматически создаваемых обработчиков событий

Создайте пустые обработчики событий щелчка для четырех кнопок в форме Филлорканцел, дважды щелкнув кнопки. При двойном щелчке кнопки также добавляется автоматически созданный код в файл кода конструктора, который позволяет нажать кнопку для вызова события.

Добавление кода для логики формы Филлорканцел

Чтобы завершить логику формы Филлорканцел, выполните следующие действия.

Перенесите следующие два пространства имен в область, чтобы не указывать полные имена их членов.

Добавьте в класс переменную и вспомогательный метод, как показано в следующем коде.

Заполните основные тексты методов для четырех обработчиков событий нажатия кнопки, как показано в следующем коде.

Тестирование приложения

Запустите приложение и попробуйте создать несколько клиентов и заказов, чтобы убедиться, что все работает правильно. Чтобы убедиться, что база данных обновлена с учетом внесенных изменений, откройте узел таблицы в Обозреватель сервера, щелкните правой кнопкой мыши узлы Customers и Orders и выберите команду отобразить данные таблицы.

Подключиться к базе данных Access ( MDB -файлу или ACCDB -файлу) можно с помощью Visual Studio. После того как определено подключение, источник данных отображается в окне Источник данных. После этого можно перетаскивать таблицы или представления в область конструктора.

если вы используете Visual Studio для подключения к базам данных Access, необходимо помнить, что версии Visual Studio до Visual Studio 2022 являются всеми 32-разрядными процессами.

это означает, что некоторые средства работы с данными в Visual Studio смогут подключаться только к базам данных Access с помощью 32-разрядных поставщиков данных.

если вы используете Visual Studio для подключения к базам данных Access, необходимо помнить, что версии Visual Studio до Visual Studio 2022 являются всеми 32-разрядными процессами. это означает, что некоторые инструменты для работы с данными в Visual Studio 2019 и более ранних версий смогут подключаться только к базам данных Access с помощью 32-разрядных поставщиков данных.

если вы используете Visual Studio 2022 для подключения к базам данных Access, необходимо помнить, что Visual Studio 2022 теперь является 64-битным процессом. это означает, что некоторые средства работы с данными в Visual Studio не смогут подключаться к базам данных Access с помощью 32-разрядных поставщиков данных.

если необходимо поддерживать 32-разрядные приложения, подключающиеся к базам данных Access, вы по-прежнему сможете создавать и запускать приложение с Visual Studio 2022. тем не менее, если необходимо использовать какие-либо инструменты Visual Studio данных, такие как обозреватель сервера, мастер источников данных или конструктор наборов данных, необходимо использовать более раннюю версию Visual Studio, которая все еще является 32-битным процессом. последняя версия Visual Studio, которая была 32-разрядным процессом, была Visual Studio 2019.

если вы планируете преобразовать проект в 64-разрядный процесс, рекомендуется использовать 64-разрядный ядро СУБД Microsoft access, также именуемый подсистемой подключения Access (ACE). Дополнительные сведения см. в разделе поставщик OLE DB для Jet и драйвер ODBC — 32-разрядные версии .

Предварительные требования

чтобы использовать эти процедуры, необходим проект Windows Forms или WPF и база данных access (accdb -файл) или база данных access 2000-2003 (mdb -файл). Выполните процедуру, соответствующую типу файла.

Создание набора данных для ACCDB-файла

Подключение к базам данных, созданным с помощью Microsoft 365, Access 2016, доступа 2013, access 2010 или access 2007 с помощью следующей процедуры.

откройте проект приложения Windows Forms или WPF в Visual Studio.

Чтобы открыть окно " Источники данных ", нажмите клавиши CTRL + Q, введите "данные" в поле поиска и выберите окно " Источники данных ". в меню вид выберите другие Windows > источники данных. Или нажмите клавиши SHIFT + ALT + D.

Снимок экрана: источники данных в поле поиска

В окне Источники данных выберите Добавить новый источник данных.

Откроется Мастер настройки источника данных .

Снимок экрана: мастер настройки источника данных

На странице Выбор типа источника данных выберите база данных , а затем нажмите кнопку Далее.

На странице Выбор модели базы данных выберите набор данных , а затем нажмите кнопку Далее.

Снимок экрана: страница

На странице Выбор подключения базы данных выберите Новое подключение для настройки нового подключения к данным.

Снимок экрана: страница

Откроется диалоговое окно Добавление соединения.

Снимок экрана: диалоговое окно

Если источник данных не установлен в файл базы данных Microsoft Access, нажмите кнопку изменить .

Снимок экрана: диалоговое окно

Введите имя пользователя и пароль (при необходимости) и нажмите кнопку ОК.

На странице Выбор подключения к данным нажмите кнопку Далее .

Снимок экрана страницы

Разверните узел Таблицы на странице Выбор объектов базы данных.

Снимок экрана: страница

Выберите таблицы или представления, которые необходимо включить в набор данных, а затем нажмите кнопку Готово.

Объект DataSet добавляется в проект, и таблицы и представления отображаются в окне Источники данных.

Снимок экрана: окно

Создание набора данных для ACCDB-файла

Подключение к базам данных, созданным с помощью Microsoft 365, Access 2016, доступа 2013, access 2010 или access 2007 с помощью следующей процедуры.

откройте проект приложения Windows Forms или WPF в Visual Studio.

Чтобы открыть окно " Источники данных ", нажмите клавиши CTRL + Q, введите "данные" в поле поиска и выберите окно " Источники данных ". в меню вид выберите другие Windows > источники данных. Или нажмите клавиши SHIFT + ALT + D.

Просмотр других окон

В окне Источники данных выберите Добавить новый источник данных.

Откроется Мастер настройки источника данных .

На странице Выбор типа источника данных выберите база данных , а затем нажмите кнопку Далее.

На странице Выбор модели базы данных выберите набор данных , а затем нажмите кнопку Далее.

Снимок экрана: страница

На странице Выбор подключения базы данных выберите Новое подключение для настройки нового подключения к данным.

Снимок экрана: страница

Откроется диалоговое окно Добавление соединения.

Снимок экрана: диалоговое окно

Если источник данных не установлен в файл базы данных Microsoft Access, нажмите кнопку изменить .

Снимок экрана: диалоговое окно

Введите имя пользователя и пароль (при необходимости) и нажмите кнопку ОК.

На странице Выбор подключения к данным нажмите кнопку Далее .

Снимок экрана страницы

Разверните узел Таблицы на странице Выбор объектов базы данных.

Выберите таблицы или представления, которые необходимо включить в набор данных, а затем нажмите кнопку Готово.

Объект DataSet добавляется в проект, и таблицы и представления отображаются в окне Источники данных.

Создание набора данных для ACCDB-файла

Подключение к базам данных, созданным с помощью Microsoft 365, доступа 2013, access 2010 или access 2007 с помощью следующей процедуры.

откройте проект приложения Windows Forms или WPF в Visual Studio.

Чтобы открыть окно " Источники данных ", нажмите клавиши CTRL + Q, введите "данные" в поле поиска и выберите окно " Источники данных ". в меню вид выберите другие Windows > источники данных. Или нажмите клавиши SHIFT + ALT + D.

В окне Источники данных выберите Добавить новый источник данных.

Откроется Мастер настройки источника данных .

На странице Выбор типа источника данных выберите база данных , а затем нажмите кнопку Далее.

На странице Выбор модели базы данных выберите набор данных , а затем нажмите кнопку Далее.

На странице Выбор подключения базы данных выберите Новое подключение для настройки нового подключения к данным.

Откроется диалоговое окно Добавление соединения.

Если источник данных не установлен в файл базы данных Microsoft Access, нажмите кнопку изменить .

Введите имя пользователя и пароль (при необходимости) и нажмите кнопку ОК.

На странице Выбор подключения к данным нажмите кнопку Далее .

Разверните узел Таблицы на странице Выбор объектов базы данных.

Выберите таблицы или представления, которые необходимо включить в набор данных, а затем нажмите кнопку Готово.

Объект DataSet добавляется в проект, и таблицы и представления отображаются в окне Источники данных.

Создание набора данных для MDB-файла

Подключение базы данных, созданные с помощью Access 2000-2003, с помощью следующей процедуры.

откройте проект приложения Windows Forms или WPF в Visual Studio.

в меню вид выберите другие Windows > источники данных.

В окне Источники данных выберите Добавить новый источник данных.

Откроется Мастер настройки источника данных .

На странице Выбор типа источника данных выберите база данных , а затем нажмите кнопку Далее.

На странице Выбор модели базы данных выберите набор данных , а затем нажмите кнопку Далее.

На странице Выбор подключения базы данных выберите Новое подключение для настройки нового подключения к данным.

Если источник данных не является файлом базы данных Microsoft Access (OLE DB), выберите изменить , чтобы открыть диалоговое окно изменение источника данных и выберите файл базы данных Microsoft Access, а затем нажмите кнопку ОК.

В поле имя файла базы данных укажите путь и имя файла MDB , к которому необходимо подключиться, а затем нажмите кнопку ОК.

Добавление файла базы данных Access для подключения

На странице Выбор подключения к данным нажмите кнопку Далее .

Разверните узел Таблицы на странице Выбор объектов базы данных.

Выберите нужные таблицы или представления в наборе данных, а затем нажмите кнопку Готово.

Объект DataSet добавляется в проект, и таблицы и представления отображаются в окне Источники данных.

Дальнейшие действия

Только что созданный набор данных доступен в окне Источники данных . Теперь можно выполнить любую из следующих задач:

выберите элементы в окне источники данных и перетащите их в форму или область конструктора (см. раздел привязка Windows Forms элементов управления к данным в Visual Studio или общие сведения о привязке данных WPF).

Откройте источник данных в Конструкторе набора данных для добавления или изменения объектов, составляющих набор данных.

Добавьте логику проверки в ColumnChanging RowChanging событие или таблиц данных в наборе данных (см. раздел Проверка данных в наборах).


Что будет в статье:

Эта статья дополняет код первой части - найти его можно здесь. Код для этой части статьи находится в репозитории по ссылке.

Если вам интересно асинхронное программирование, приходите к нам на курс в KTS, где мы подробно разберем эту тему. Старт — 18 октября.

1 — Поднимаем базу данных PostgreSQL в Docker-контейнере

Это подготовительный этап. Мы будем работать с сервером PostgreSQL версии 11 и старше. Так как Docker все равно понадобится вам для последующей публикации приложения в Интернете, то убьем двух зайцев сразу и запустим сервер PostgreSQL в Docker-контейнере.

Docker-контейнеры по умолчанию не хранят данные, поэтому необходимо создать volume, чтобы не потерять данные нашей базы после перезапуска или после остановки контейнера:

Теперь запустим нашу базу командой:

Мы запустили docker-контейнер с базой данных от имени root-пользователя. Давайте рассмотрим переданные параметры:

-e POSTGRES_PASSWORD=forum_password — задали пароль для пользователя базы данных, передав его через переменную окружения в контейнер

-e POSTGRES_USER=forum_user — задали имя пользователя базы данных аналогичным способом

-p 5432:5432 — опубликовали 5432-ой порт контейнера во внешнюю среду. Подробнее о том, как устроена сеть Docker, можно прочитать тут

--mount source=postgres-data,target=/var/lib/postgresql — примонтировали volume postgres-data к нашему контейнеру. Теперь все данные, которые приложение в контейнере записало в /var/lib/postgresql , сохранятся на жестком диске. Иначе при остановке или перезапуске контейнера мы бы их потеряли.

-d — запустили команду docker run в detached-режиме: можем закрыть консоль, а контейнер продолжит работать

postgres:11 — имя образа, на основе которого необходимо запустить контейнер. Подробнее про docker-образы можно прочитать здесь

Проверим, что база работает. Для этого подключимся к ней через CLI:

Создадим базу данных и дадим все права на нее нашему пользователю:

Подготовка закончена, переходим к написанию приложения.

2 — Создаем модель данных

Чтобы получить доступ к базе данных, нам нужен адрес ее сервера, имя и пароль для входа, а также название самой базы. При локальной разработке приложения на компьютере эти параметры могут быть одни, а при публикации в Интернете совершенно другие. Данные, которые могут меняться, обычно выносят в конфигурационный файл и подменяют этот файл в зависимости от окружения.

В корень проекта добавим папку config, а в ней создадим файл config.yaml. Также сразу же создадим файл settings.py в папке app. Структура проекта должна выглядеть следующим образом:

3 — Работаем с файлами конфигурации приложения

В файл config.yaml добавим следующую конфигурацию:

Теперь нам надо научиться как-то работать с этими данными. Для этого откроем файл app/settings.py и запишем в него:

Теперь в глобальной переменной config хранится словарь с конфигурацией. Например, чтобы получить порт, нам нужно обратиться к config[“common”][“port”] .

Давайте прикрепим config к нашему приложению. Приведем файл main.py к следующему виду:

После этого шага мы можем обратиться к app[“config”] и получить доступ к нашему конфигурационному файлу из любого места в приложении.

4 — Подключаемся к базе данных и пишем свой Accessor

Аксессор — сущность, которая помогает работать с данными, находящимися вне памяти приложения, например, бывает аксессор к базе данных или аксессор к стороннему API. В аксессоре сокрыты детали реализации, такие как установка соединения, выполнение SQL-команд, парсинг ответа и т.д. Остальной код приложения не должен "знать" о реализации того или иного метода аксессора, он просто должен вызвать метод и взаимодействовать со сторонним источником данных в удобной форме.

Давайте создадим подключение к базе данных. Для этого в папке app/ создадим еще один модуль store/, в которой будут хранится наши аксессоры. Добавим в папку app/store/database три файла и не забудем добавить файл __init__.py в store/database:

accessor.py — здесь будет располагаться код для подключения к базе

models.py — здесь находится входная точка для наших моделей, о которых будет сказано ниже

Теперь структура вашего проекта должна выглядеть следующим образом:

Файлы __init__.py оставьте пустыми, они нужны лишь как признак python-модуля.

В файл accessor.py добавим следующий код:

Давайте кратко рассмотрим содержание этого файла. Мы создали класс PostgresAccessor , который отвечает за подключение к базе данных и отключение после завершения работы.

Функция _on_connect берет данные о базе из конфигурационного файла и с помощью команды db.set_bind(self.config[“database_url”]) создает необходимое подключение к базе. Если указана неверная конфигурация базы, или по какой-то причине подключение невозможно, то функция бросит исключение, и сервер не запустится.

Важно, чтобы проблемы с подключением к необходимым для работы сторонним сервисам были видны на этапе запуска приложения — это позволит сразу же среагировать на проблему или откатиться к предыдущей версии приложения, а потом уже решать проблему.

Функция _on_disconnect позволяет отключиться от базы после завершения работы приложения и освободить ресурсы базы, например “правильно” разорвать соединение с ней.

5 — Инстанцируем Gino

Теперь в models.py нужно добавить код:

Это очень важный файл. Он инстацирует экземпляр Gino, с помощью которого мы можем выполнять команды в базе и еще множество других вещей. Мы создаем экземпляр Gino глобально, так как он необходим для проведения миграций.

Чтобы понять, что такое Gino и зачем он нужен, посмотрите на картинку ниже. Зеленым цветом обозначены асинхронные объекты, а желтым — синхронные:


Разберемся по шагам.

1. База данных слева может получать команды и отдавать данные по так называемому DB API, которое основано на собственном протоколе работы.

2. Чтобы выполнить SQL-скрипт из Python, необходимо установить пакет, который умеет работать с DB API. Самый популярный пакет — Psycopg. Но проблема в том, что он синхронный: когда запрос уйдет в базу, необходимо дождаться ответа. Во время ожидания никакой другой код выполнен не будет. Для решения этой проблемы создан Asyncpg — обертка над Psycopg, которая позволяет сделать его асинхронным.

Важно понимать, зачем необходимо асинхронное соединение с базой данных. Пример: мы решили посчитать статистику всех продаж магазина за несколько лет. База выполняет подсчет за 20 секунд. На эти 20 секунд синхронный python-код остановит свою работу и не сможет обрабатывать запросы от других пользователей. Говоря по-простому, сервер просто «зависнет». Асинхронное соединение «заморозит» дальнейшее выполнение функции, сделавшей запрос к базе, пока не дождется ответа, и продолжит выполнять другую работу — например, обслуживать другие запросы клиентов.

3. Достаточно неудобно писать SQL-команды вручную. Гораздо быстрее, надежнее и безопаснее писать с использованием Python-кода, хотя из-за этого немного теряется производительность. Для этого существует пакет SQLAlchemy, который позволяет удобно работать с базой, генерируя SQL-команды по нашему Python-коду и не только. К сожалению, по умолчанию SQLAlchemy синхронный пакет, поэтому появляется необходимость в еще одной обертке — Gino.

4. Gino — последнее звено, после которого наше асинхронное приложение наконец-то может асинхронно общаться с базой.

SQLAlchemy, начиная с версии 1.4 поддерживает asyncio "из коробки", поэтому острая необходимость в Gino в асинхронных приложениях отпадает. Но Gino продолжает развиваться и добавляет функционал в SQLAlchemy, поэтому не стоит сбрасывать его со счетов. Подробнее о жизни после SQLAlchemy 1.4 можно прочитать здесь.

Осталось привязать к нашему приложению PostgresAccessor. Добавим подключение аксессора в main.py, написав функцию setup_accessors и изменив код setup_app:

В реляционных базах данных информация хранится в таблицах. Работать с ними не совсем удобно. Чтобы сделать работу с данными более удобной и прозрачной, создают модели — некие абстракции над данными, которые человек воспринимает лучше, чем строка таблицы. Удобство не единственная причина использования моделей, они также позволяют задавать структуру базы данных из кода и добавляют уровень абстракции.

Хранить эти данные мы будем в таблице Message:


Конечно, можно создать эту таблицу вручную, но это не очень удобно и безопасно при запуске приложения из нового места или если проект ведут несколько разработчиков. Если из-за ошибок в коде структуры базы данных будут несколько различаться это может привести к серьезным и трудно-исправляемым сбоям сервиса. Миграции призваны решить данную проблему.

Миграции — это набор операций, которые надо применить к базе, чтобы привести ее в необходимое состояние. С помощью них можно как повысить, так и понизить версию структуры базы данных.
Пример: можно выполнить миграцию и создать новые таблицы, а в случае ошибки откатить миграцию обратно и удалить таблицы.

При таком подходе несколько разработчиков могут изменять структуру базы параллельно — каждый создает необходимые ему миграции, а во время слияния кода эти миграции объединяются и дают структуру базы, которая удовлетворяет всем новым условиям. Если же мы планируем запустить наше приложение в новом месте, то достаточно выполнить все миграции, чтобы получить новейшую структуру базы.

Подошло время написать нашу первую модель Message. Для этого в папке forum/ создадим файл models.py и вставим в него следующий код:

Этим кодом мы декларативно задали, данные каких типов хотим хранить в таблице message. Также наша модель стала наследником db.Model , где db — экземпляр Gino. Теперь у нас все готово, чтобы сгенерировать первую миграцию.

7 — Генерируем миграцию

Когда нам нужна работа с миграциями, на помощь приходит пакет Alembic. Он позволяет автоматизировать процесс применения миграции и их создание.

Наша миграция будет содержать создание таблицы message со всеми необходимыми полями. Для этого в корне нашего проекта выполним следующую команду:

Если все правильно, в корне вашего проекта должны появиться директорий migrations и файл alembic.ini. Alembic может работать, ничего не зная о наших моделях, которые заданы в коде — но тогда теряется возможность автоматической генерации миграций. Чтобы дать возможность Alembic «познакомиться» с нашим кодом, необходимо сделать два действия:

В файле alembic.ini заменить строку

и сохранить файл.

2. Заменить код файла migrations/env.py на следующий:

Этими действиями мы привязали к конфигурации Alembic конфигурацию нашего приложения. Теперь Alembic знает о наших моделях.

Чтобы сгенерировать миграцию, надо в корне выполнить следующие команды:

Команда export необходима, чтобы Alembic смог понять, о каком приложении мы говорим, так как оно может не находиться в PYTHONPATH — директориях, где python ищет свои модули.

Флаг -m во второй команде позволяет задать человекочитаемое название миграции, чтобы сделать назначение миграции понятнее.

Если все прошло успешно, то в папке migrations/versions появится файл примерно с таким названием: 6356fd90ab82_create_table_message.py. Код в начале названия — уникальный идентификатор миграции, который используется для сопоставления миграции и состояния базы, а также для того, чтобы обеспечить верный порядок применения миграций.

Давайте рассмотрим фрагменты этого файла более детально:

revision — тот же код, который хранится в названии

down_revision — код миграции, которую надо применить для того, после этой при понижении версии базы. Сейчас он пустой, так как это первая миграция в нашем проекте.

branch_labels — указывается, если несколько миграций должны быть выполнены после одной и той же родительской миграции — это может произойти например при слиянии кода нескольких разработчиков, которые создали миграции для одной и той же таблицы.

Также стоит рассмотреть две функции из этого файла: upgrade() — вызывается при повышении версии базы данных, а downgrade() — при понижении.

Повысим версию нашей базы до последней:

Теперь при прямом подключении к БД мы можем увидеть созданную структуру:


8 — Alembic: добавляем взаимодействие с базой данных

В последнем шаге на сегодня рассмотрим взаимодействие с базой данных: получение и создание записей. Для этого необходимо создать новый View в файле app/forum/views.py. Добавьте этот код в конец файла:

Не забудьте указать путь, по которому будет доступен данный View. В файле app/forum/routes.py в функции setup_routes() добавьте:

Теперь выполните команды:

С помощью команды \c мы подключаемся к конкретной базе данных и можем выполнять запросы к ее таблицам, например, выполнить команду INSERT .

Чтобы посмотреть имеющиеся таблицы в базе данных, после подключения к ней необходимо выполнить команду \d :

Заметьте, что у нас существуют две таблицы и одна последовательность:

alembic_version — в ней хранится номер последней примененной к базе миграции, которая должна соответствовать префиксу в последнем примененном файлом миграции:

Теперь, запустив наше приложение командой python main.py в корне проекта и перейдя в браузер по ссылке 0.0.0.0:8080/api/messages.list, мы должны увидеть такую картину:


Готово! Мы получили данные, которые хранятся в нашей базе и передали их в ответ на запрос.

Чтобы добавить данные не вручную, создайте еще один View. Откройте файл app/forum/views.py и добавьте в конец следующий код:

Добавим путь к нашему новому View в app/forum/routes.py в функции setup_routes() :

9 — Добавляем новые возможности в интерфейс


Теперь откроем в браузере 0.0.0.0:8080 и увидим следующее:


10 — Резюме

Подведем итоги. В этой статье мы:

Научились поднимать базу данных PostgreSQL в Docker-контейнере

Поработали с файлами конфигурации приложения

Написали свой Accessor, который позволил нашему приложению получать данные из сторонних источников. По аналогии с ним можно создать каналы получения данных из других источников, например из стороннего API.

Создали модель Message, абстракцию над «сухой» строчкой в таблице базы данных

Узнали как асинхронно общаться с PostgreSQL из Python

Настроили alembic и с его помощью сгенерировали первую миграцию

Код для второй части статьи находится в этом репозитории.

Асинхронное программирование — большая тема. Если хотите разобраться в ней подробнее, приходите к нам на курс. Занятия начнутся 18 октября, а 22 сентября мы проведем вебинар, на котором расскажем, что будет в программе.

Читайте также: