Продолжаем писать библиотеку для быстрого доступа к базе данных SQLite. В первой части мы написали помощников для получения данных. Сегодня же рассмотрим вставку данных в базу.
Реализация
Перед тем, как написать основной метод, нам понадобятся два класса, объекты которых мы будем передавать в главный метод. Почему я называю его главным? Наверное потому, что в отличии от запросов выборки из базы, метод вставки у нас один и достаточно сложный.
Первый класс – класс параметра для SQLiteCommand. Он содержит 3 поля: название поля(колонки), в которую будет вставлено значение; само значение; тип вставляемого значения. Ниже я опишу, зачем задавать тип значения. Смотрим первый класс:
14 |
get { return _value; } |
15 |
set { _value = value; } |
19 |
/// Название поля в базе данных |
21 |
public string ColumnName |
23 |
get { return _columnName; } |
24 |
set { _columnName = value; } |
28 |
/// Тип передаваемого значения |
32 |
get { return _dbType; } |
33 |
set { _dbType = value; } |
Думаю, тут все понятно. Второй класс нужен для хранения наших параметров в виде коллекции. Эту коллекцию мы и будем передавать в главный метод. Смотрим второй класс:
1 |
class ParametersCollection : CollectionBase |
4 |
/// Добавить параметр в коллекцию |
6 |
/// <param name="iparam">Новый параметр</param> |
7 |
public virtual void Add(Parameter iparam) |
10 |
this.List.Add(iparam); |
14 |
/// Добавить параметр в коллекцию |
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) |
22 |
Parameter iparam = new Parameter(); |
24 |
iparam.ColumnName = columnName; |
28 |
iparam.DbType = dbType; |
31 |
this.List.Add(iparam); |
35 |
/// Получить элемент по индексу |
37 |
/// <param name="Index">Индекс</param> |
38 |
/// <returns>Параметр</returns> |
39 |
public virtual Parameter this[int Index] |
45 |
return (Parameter)this.List[Index]; |
В этом классе два конструктора. Первый принимает объект в виде параметра, второй – 3 параметра в виде значений. В нашем проекте коллекция создается следующим образом:
2 |
ParametersCollection collection = new ParametersCollection(); |
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); |
10 |
db.Insert("test", collection); |
Как видите, я использую второй конструктор.
Классы для использования параметров созданы. Смотрим основной метод:
1 |
public void Insert(string databasename, ParametersCollection parameters) |
3 |
ConnectionState previousConnectionState = ConnectionState.Closed; |
4 |
using (SQLiteConnection connect = new SQLiteConnection(ConnectionString)) |
8 |
previousConnectionState = connect.State; |
9 |
if (connect.State == ConnectionState.Closed) |
13 |
SQLiteCommand command = new SQLiteCommand(connect); |
15 |
string queryColumns = "("; |
16 |
string queryValues = "("; |
17 |
foreach (Parameter iparam in parameters) |
20 |
command.Parameters.Add("@" + iparam.ColumnName, iparam.DbType).Value = iparam.Value; |
24 |
queryColumns += iparam.ColumnName; |
25 |
queryValues += "@" + iparam.ColumnName; |
30 |
queryColumns += "," + iparam.ColumnName; |
31 |
queryValues += ",@" + iparam.ColumnName; |
37 |
string sql = string.Format("INSERT INTO {0} {1} VALUES {2}", databasename, queryColumns, queryValues); |
38 |
command.CommandText = sql; |
39 |
command.ExecuteNonQuery(); |
41 |
catch (Exception error) |
43 |
System.Windows.Forms.MessageBox.Show(error.Message, "Ошибка при вставке нового значения", MessageBoxButtons.OK, MessageBoxIcon.Error); |
47 |
if (previousConnectionState == ConnectionState.Closed) |
Метод требует 2 параметра – имя базы данных и коллекцию параметров. Выполняем подключение к базе. Создаем две переменных queryColumns и queryValues. В них будут содержаться строки для общей строки запроса типа «(колонка1, колонка2, колонка3)», для списка полей, и «(@колонка1, @колонка2, @колонка3)», для списка значений. foreach проходит по коллекции и мы можем обработать каждый параметр. Теперь я объясняю зачем требуется указывать тип значения. Метод Add в command.Parameters принимается два аргумента – имя поля со знаком @, который соответствует имени в строке запроса, и тип значения, которое будет вставлено. Если вставлять напрямую, например, создавая запрос типа «INSERT INTO test (title, status) VALUES (‘dfa,df’\»,»,2)», то произойдет ошибка. Вставляя значения через параметры, мы тем самым избавляем себя от последующих проблем. Все проверки экранирования служебных символов берет на себя библиотека через которую мы «общаемся» с базой. В итоге, мы собираем полный запрос и выполняем его. После выполнения, при любых обстоятельствах, пробуем закрыть соединение.
Заключение
Сегодня мы рассмотрели метод вставки данных в таблицу. До совершенства ему далеко. Многое не учтено. Но для простой работы этого достаточно. Например, эта реализация не позволяет вставить в виде значения результат команды DATETIME(‘NOW’) или какой-либо другой.