• Программинг

Нужны источники бесперебойного питания?

Источники бесперебойного питания от дизельстор

C# библиотека удобного доступа к базе данных SQLite. Часть 2

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

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

Первый класс – класс параметра для SQLiteCommand. Он содержит 3 поля: название поля(колонки), в которую будет вставлено значение; само значение; тип вставляемого значения. Ниже я опишу, зачем задавать тип значения. Смотрим первый класс:

1 class Parameter
2 {
3     #region Поля
4     string _columnName;
5     object _value;
6     DbType _dbType;
7     #endregion
8  
9     /// <summary>
10     /// Значение
11     /// </summary>
12     public object Value
13     {
14         get { return _value; }
15         set { _value = value; }
16     }
17  
18     /// <summary>
19     /// Название поля в базе данных
20     /// </summary>
21     public string ColumnName
22     {
23         get { return _columnName; }
24         set { _columnName = value; }
25     }
26  
27     /// <summary>
28     /// Тип передаваемого значения
29     /// </summary>
30     public DbType DbType
31     {
32         get { return _dbType; }
33         set { _dbType = value; }
34     }
35 }

Думаю, тут все понятно. Второй класс нужен для хранения наших параметров в виде коллекции. Эту коллекцию мы и будем передавать в главный метод. Смотрим второй класс:

1 class ParametersCollection : CollectionBase
2 {
3     /// <summary>
4     /// Добавить параметр в коллекцию
5     /// </summary>
6     /// <param name="iparam">Новый параметр</param>
7     public virtual void Add(Parameter iparam)
8     {
9         //добавляем в общую коллекцию
10         this.List.Add(iparam);
11     }
12  
13     /// <summary>
14     /// Добавить параметр в коллекцию
15     /// </summary>
16     /// <param name="columnName">Имя поля/колонки</param>
17     /// <param name="value">Значине</param>
18     /// <param name="dbType">Тип значения</param>
19     public virtual void Add(string columnName, object value, DbType dbType)
20     {
21         //Инициализируем объект с параметром
22         Parameter iparam = new Parameter();
23         //присваиваем название поля
24         iparam.ColumnName = columnName;
25         //присваиваем значение
26         iparam.Value = value;
27         //присваиваем тип значения
28         iparam.DbType = dbType;
29         //добавляем в общую коллекцию
30         //List описан в "родителе"
31         this.List.Add(iparam);
32     }
33  
34     /// <summary>
35     /// Получить элемент по индексу
36     /// </summary>
37     /// <param name="Index">Индекс</param>
38     /// <returns>Параметр</returns>
39     public virtual Parameter this[int Index]
40     {
41         get
42         {
43             //возвращает элемент по индексу
44             //используется в конструкции foreach
45             return (Parameter)this.List[Index];
46         }
47     }
48 }

В этом классе два конструктора. Первый принимает объект в виде параметра, второй – 3 параметра в виде значений. В нашем проекте коллекция создается следующим образом:

1 //создаем коллекцию параметров
2 ParametersCollection collection = new ParametersCollection();
3 //каждый параметр создаем по следующей схеме
4 //один Add - один параметр
5 collection.Add("title", "проверка '\"вставки с кавычками\"", DbType.String);
6 collection.Add("status", 1, DbType.Boolean);
7 collection.Add("topic_id", 50, DbType.Int32);
8 collection.Add("testdate", DateTime.Now, DbType.Date);
9 //вставляем в базу
10 db.Insert("test", collection);

Как видите, я использую второй конструктор.

Классы для использования параметров созданы. Смотрим основной метод:

1 public void Insert(string databasename, ParametersCollection parameters)
2 {
3     ConnectionState previousConnectionState = ConnectionState.Closed;
4     using (SQLiteConnection connect = new SQLiteConnection(ConnectionString))
5     {
6         try
7         {
8             previousConnectionState = connect.State;
9             if (connect.State == ConnectionState.Closed)
10             {
11                 connect.Open();
12             }
13             SQLiteCommand command = new SQLiteCommand(connect);
14             bool ifFirst = true;
15             string queryColumns = "("; //список полей, в которые вставляются новые значения
16             string queryValues = "("//список значений для этих полей
17             foreach (Parameter iparam in parameters)
18             {
19                 //добавляем новый параметр
20                 command.Parameters.Add("@" + iparam.ColumnName, iparam.DbType).Value = iparam.Value;
21                 //собираем колонки и значения в одну строку
22                 if (ifFirst)
23                 {
24                     queryColumns += iparam.ColumnName;
25                     queryValues += "@" + iparam.ColumnName;
26                     ifFirst = false;
27                 }
28                 else
29                 {
30                     queryColumns += "," + iparam.ColumnName;
31                     queryValues += ",@" + iparam.ColumnName;
32                 }
33             }
34             queryColumns += ")";
35             queryValues += ")";
36             //создаем новый запрос
37             string sql = string.Format("INSERT INTO {0} {1} VALUES {2}", databasename, queryColumns, queryValues);
38             command.CommandText = sql;
39             command.ExecuteNonQuery();
40         }
41         catch (Exception error)
42         {
43             System.Windows.Forms.MessageBox.Show(error.Message, "Ошибка при вставке нового значения", MessageBoxButtons.OK, MessageBoxIcon.Error);
44         }
45         finally
46         {
47             if (previousConnectionState == ConnectionState.Closed)
48             {
49                 connect.Close();
50             }
51         }
52     }
53 }

Метод требует 2 параметра – имя базы данных и коллекцию параметров. Выполняем подключение к базе. Создаем две переменных queryColumns и queryValues. В них будут содержаться строки для общей строки запроса типа «(колонка1, колонка2, колонка3)», для списка полей, и «(@колонка1, @колонка2, @колонка3)», для списка значений. foreach проходит по коллекции и мы можем обработать каждый параметр. Теперь я объясняю зачем требуется указывать тип значения. Метод Add в command.Parameters принимается два аргумента – имя поля со знаком @, который соответствует имени в строке запроса, и тип значения, которое будет вставлено. Если вставлять напрямую, например, создавая запрос типа «INSERT INTO test (title, status) VALUES (‘dfa,df’\»,»,2)», то произойдет ошибка. Вставляя значения через параметры, мы тем самым избавляем себя от последующих проблем. Все проверки экранирования служебных символов берет на себя библиотека через которую мы «общаемся» с базой. В итоге, мы собираем полный запрос и выполняем его. После выполнения, при любых обстоятельствах, пробуем закрыть соединение.
Заключение

Сегодня мы рассмотрели метод вставки данных в таблицу. До совершенства ему далеко. Многое не учтено. Но для простой работы этого достаточно. Например, эта реализация не позволяет вставить в виде значения результат команды DATETIME(‘NOW’) или какой-либо другой.