Предисловие
Итак, после долгих мучений с различными базами данных, было решено написать что-то такое, что могло упростить разработку приложения, работающего с какой-либо базой данных. Я заметил, что в каждом моем проекте приходится писать одно и тоже, когда это касается получения, вставки и т.д. в базу. Разбирая ZEND FRAMEWORK наткнулся на готовый класс, который значительно упрощал доступ к данным, хранящихся в базе. Решение, конечно, не для кул-хацкеров, но для написания повседневных программ «для себя» и «для других» подходит. Это первая часть в цикле статей, в которых, шаг за шагом будем создавать класс, призванный помочь в решении поставленной задачи.
Инструментарий
Для первой части я создал простой проект. Скажу сразу: в роли подопытной базы данных будем использовать SQLITE. Ей не нужен сервер, а для теста нашего класса ее хватит. Если вам понадобиться использовать класс для работы с MSSQL или MYSQL, то можно будет очень просто и быстро произвести нужные замены в классе.
Библиотеку SQLITE я приложил к проекту. Она 32-битная. 64-битную версию ищите здесь.
Реализация
Ядро нашего проекта – это файл dbFacade.cs. В нем будет описываться вся работа с базой данных. Этот файлы вы можете копировать в другой проект и пользоваться им как родным.
Давайте теперь рассмотрим структуру файла. Первая версия будет только создавать новый файл со структурой базы и читать его.
Основные настройки. Задаем сразу, чтобы потому не морочить себе голову.
2 |
public static string filename = Path.Combine(Application.StartupPath, "working.db"); |
4 |
string ConnectionString = string.Format("data source={0};New=True;UseUTF16Encoding=True", filename); |
7 |
Первая важная функция создает файл со структурой. |
9 |
public void CreateDatabase() |
12 |
string sql_test = @"CREATE TABLE 'Test'( |
13 |
'id' INTEGER PRIMARY KEY AUTOINCREMENT, |
17 |
'testdate' datetime NOT null DEFAULT '2009-10-07')"; |
20 |
string sql_createindex = "CREATE UNIQUE INDEX testdate_indx ON Test (testdate)"; |
22 |
ConnectionState previousConnectionState = ConnectionState.Closed; |
23 |
using (SQLiteConnection connect = new SQLiteConnection(ConnectionString)) |
28 |
previousConnectionState = connect.State; |
29 |
if (connect.State == ConnectionState.Closed) |
35 |
SQLiteCommand command = new SQLiteCommand(sql_test, connect); |
36 |
command.ExecuteNonQuery(); |
39 |
command.CommandText = sql_createindex; |
40 |
command.ExecuteNonQuery(); |
46 |
if (previousConnectionState == ConnectionState.Closed) |
Смотрите, SQLiteConnection, если его просто переименовать в SQLConnection, то это будет уже работа с MSSQL. Также и SQLiteCommand меняется на SQLCommand. И ВСЕ! После этих смен, эта функция уже будет работать с MSSQL. Вот так все просто… пока просто :)
Далее… вторая функция. Простая функция. Достает все данные из всех столбцов. Можно с условиями и различными параметрами. Т.е. простой запрос, без всяких там связываний с другими таблицами и т.д.
1 |
public DataTable FetchAll(string databasename, string where, string etc) |
3 |
DataTable dt = new DataTable(); |
5 |
string sql = string.Format("SELECT * FROM {0} {1} {2}", databasename, where, etc); |
6 |
ConnectionState previousConnectionState = ConnectionState.Closed; |
7 |
using (SQLiteConnection connect = new SQLiteConnection(ConnectionString)) |
11 |
previousConnectionState = connect.State; |
12 |
if (connect.State == ConnectionState.Closed) |
16 |
SQLiteCommand command = new SQLiteCommand(sql, connect); |
17 |
SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); |
21 |
catch (Exception error) { |
22 |
System.Windows.Forms.MessageBox.Show(error.Message, "Ошибка при получении данных из базы", MessageBoxButtons.OK, MessageBoxIcon.Error); |
26 |
if (previousConnectionState == ConnectionState.Closed) |
Это была простая функция, для простого запроса. То, что она большая, так это просто куча проверок различных.
И еще одна функция для получения данных из избранных колонок:
1 |
public DataTable FetchByColumn(string databasename, string[] columns, string where, string etc) |
3 |
DataTable dt = new DataTable(); |
4 |
string textofcolumns = string.Empty; |
6 |
if (columns == null || columns.Length == 0) |
12 |
foreach (string col in columns) |
20 |
textofcolumns += "," + col; |
24 |
string sql = string.Format("SELECT {0} FROM {1} {2} {3}", textofcolumns, databasename, where, etc); |
25 |
ConnectionState previousConnectionState = ConnectionState.Closed; |
26 |
using (SQLiteConnection connect = new SQLiteConnection(ConnectionString)) |
30 |
previousConnectionState = connect.State; |
31 |
if (connect.State == ConnectionState.Closed) |
35 |
SQLiteCommand command = new SQLiteCommand(sql, connect); |
36 |
SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); |
39 |
catch (Exception error) |
41 |
System.Windows.Forms.MessageBox.Show(error.Message, "Ошибка при получении данных из базы", MessageBoxButtons.OK, MessageBoxIcon.Error); |
46 |
if (previousConnectionState == ConnectionState.Closed) |
В эту функция мы передаем массив из колонок. Разбираем его, создаем запрос, выполняем. Отличается от предыдущей функции только передачей массива колонок.
Дополнительно описаны функции без передачи некоторых параметров. Типа:
1 |
public DataTable FetchAll(string databasename) |
3 |
return FetchAll(databasename, "", ""); |
и
1 |
public DataTable FetchAll(string databasename, string where) |
3 |
return FetchAll(databasename, where, ""); |
Вот и разобрали первую версию чудо-библиотеки.
К проекту приложена простенькая заполненная база данных working.db. Просто для наглядности.