DPaul1994 Ответов: 1

База данных C# SQLite заблокирована


У меня есть простой код обновления, но я не знаю, по каким причинам он не работает. Я получаю: база данных заблокирована. Кто-нибудь может мне помочь? Это и есть код:
try
                       {
                           SQLiteCommand sel1 = new SQLiteCommand("select totalsim from accounts where username='DPaul'",Conexiune.getConnection());
                           SQLiteDataReader readt = sel1.ExecuteReader();
                           while (readt.Read())
                           {
                               int totalsimm = Convert.ToInt32(readt["totalsim"]);
                               totalsimm++;
                               using (SQLiteCommand update = new SQLiteCommand("UPDATE accounts SET totalsim=@totalsimm where username = 'DPaul'", Conexiune.getConnection()))
                               {
                                   update.Parameters.Add(new SQLiteParameter("@totalsimm", totalsimm));
                                   Int32 rows = update.ExecuteNonQuery();
                               }
                           }
                       }
                       catch (Exception ex)
                       {
                           MessageBox.Show(ex.Message);
                       }


У меня есть еще один выбор, но он находится в отдельной функции.

1 Ответов

Рейтинг:
9

OriginalGriff

Ты не можешь этого сделать.
У вас есть открытое соединение для обработки считывателя во внешнем пространстве while цикл, и вы пытаетесь обновить ту же таблицу из того же соединения внутри этого цикла - эти операции несовместимы, поэтому вы получаете ошибку "база данных заблокирована".

Лучшим решением было бы сбросить считыватель и загрузить DataTable через DataAdapter, а затем использовать DataTable data для цикла и выполнения инструкций UPDATE.


"Ну, это не о том, что я сдаюсь, меня тошнит от этого обновления :)) Я пытался изменить код многими способами, но безуспешно. Это моя последняя попытка. Я получаю ту же ошибку. Я попытался закрыть и снова открыть соединение, чем закрыть снова, но безрезультатно. Я пробовал с DataAdapter, с DataReader, но это не сработало. Я не знаю, что еще можно попробовать. И я должен изменить только значение из одной строки, не понимаю, зачем использовать цикл foreach.."

Почему цикл foreach? Потому что запрос любой формы возвращает несколько строк - которые могут быть равны нулю (если нет совпадения), одному (если есть только одно) или нескольким (если есть более одного значения) - и это всегда хорошая практика, чтобы не предполагать, что он вернет один и только один, даже если логика вашей программы говорит, что это будет. Ошибки в данных случаются! :смеяться:

Так что начните с помощью объекта dataadapter, а не объект DataReader:

string collect = "SELECT option1,option2,option3 FROM questions WHERE question=@QU";
SQLiteCommand comp = new SQLiteCommand(collect, Conexiune.getConnection());
comp.CommandType = CommandType.Text;
comp.Parameters.AddWithValue("@QU", SimulatorManager.Intrebare);
SQLiteDataAdapter da = new SQLiteDataAdapter(comp);
DataTable dt = new DataTable();
da.Fill(dt);
foreach (DataRow row in dt.Rows)
    {
    ...
    }

(Я внес некоторые изменения в то, как вы это сделали: SQL-глаголы обычно пишутся в верхнем регистре, чтобы их было легче выбрать из SQL-оператора. И никогда, никогда не объединяйте строки для формирования SQL - оператора-этот способ приводит к атакам SQL-инъекций, которые могут повредить или уничтожить вашу базу данных, просто введя текстовые поля. Всегда используйте параметризованные запросы!)

Затем в цикле вы просто используете информацию о строке, чтобы решить, нужно ли обновление:
int op1 = (int)row["option1"];
int op2 = (int)row["option2"];
int op3 = (int)row["option3"];
...


Есть ли смысл до сих пор?


DPaul1994

- Ты имеешь в виду вот так?
используя (обновление SQLiteDataAdapter = новый SQLiteDataAdapter("обновление totalsim от счета totalsim=totalsim+1 DPaul, где имя пользователя =''", Conexiune.метод getconnection()))
{
DataTable updt = новый DataTable();
обновление.Заполнить(интернета);
}

Потому что я попробовал это и получил:
Логическая ошибка SQL или отсутствующая база данных рядом с "from": синтаксическая ошибка

OriginalGriff

Вы проверили свой синтаксис SQL? :смеяться:
Обновите набор таблиц mytable ...
Нет
Обновить столбец mycolumn компонент компонент из таблицы mytable ...

DPaul1994

Омг! =)))) Да, извини за это. Но база данных по-прежнему заблокирована.

OriginalGriff

Это может быть глупый вопрос, но у вас все еще есть DataReader там? Покажите точный код, пожалуйста!

DPaul1994

Ну, это может быть глупый ответ, но это весь код :))) Я действительно не знаю, как использовать datatable..да :))

OriginalGriff

Нет, я подозреваю, что он все еще находится внутри цикла while, используя DataReader!

DPaul1994

Итак, используя SQLiteCommand, внутри этого - используя SQLiteDataReader - используя SQLiteDataAdapter и вот таблица?

OriginalGriff

Нет.
Используйте адаптер для заполнения таблицы из команды SELECT вместо DataReader, а затем используйте цикл foreach для доступа к строкам DataTable. Затем используйте команду SqLiteCommand внутри цикла для выполнения обновления.
Таким образом, при попытке выполнить обновление читатель не открывается, так как адаптер считывает и возвращает все строки сразу - читатель этого не делает, и именно поэтому SqLite жалуется.

DPaul1994

Хорошо, я попробую это сделать :)

DPaul1994

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

OriginalGriff

Вы ничего не добьетесь, если будете все время сдаваться! :смеяться:
Давайте сделаем это в несколько простых этапов.
Какой код вы получили для своего выбора, используя DataAdapter?

DPaul1994

Ну, это не о том, что я сдаюсь, меня тошнит от этого обновления :)) Я пытался изменить код многими способами, но безуспешно. Это моя последняя попытка. Я получаю ту же ошибку. Я попытался закрыть и снова открыть соединение, чем закрыть снова, но безрезультатно. Я пробовал с DataAdapter, с DataReader, но это не сработало. Я не знаю, что еще можно попробовать. И я должен изменить только значение из одной строки, не понимаю, зачем использовать цикл foreach..
<pre lang="c#">
частный недействительными UpdateTotalSim()
{
используя (SQLiteCommand команду cmd = новый SQLiteCommand(@"приходится обновлять набор totalsim=totalsim+1 Где UserName='" + SimulatorManager.Утилизатор + "'", Conexiune.getConnection()))
{
пробовать
{
УМК.Метод executenonquery();
}
поймать (исключение бывший)
{
Ящик для сообщений.Показать(напр.сообщение);
}
}
}

частный недействительными button4_Click(объект отправителя, EventArgs в электронной)
{
если (check1.Проверено == true) result1 = 1;
еще результат1 = 0;
если (check2.Проверено == true) result2 = 1;
еще результат2 = 0;
если (check3.Проверено == true) result3 = 1;
еще result3 = 0;
строка collect = "Select option1,option2,option3 from questions where `question`='" + SimulatorManager.Intrebare + "'";
SQLiteCommand комп = новый SQLiteCommand(сбор, Conexiune.метод getconnection());
компания.Свойство Commandtype = Значение Commandtype.Текст;
SQLiteDataReader read = comp.ExecuteReader(CommandBehavior.Значение closeconnection);
пробовать
{
в то время как (читай.Прочитай())
{
int op1 = (int)читать["option1"];
int op2 = (int)читать["option2"];
int op3 = (int)читать["option3"];
если (check1.Checked == false && check2.Checked == false && check3.Проверено == ложь)
Ящик для сообщений.Шоу("Selectati minim o optiune");
еще
{
если ((результат1 == ОР1) и усилитель; & (результат2 == ампер еп2) &;&ампер; (result3 == op3 отображается))
{
правильно++;
label4.Текст = правильно.Метод toString();
проверка 1.Проверено = ложь;
проверка2.Проверено = ложь;
чек-3.Проверено = ложь;
выбирать();
}
еще
{
некорректное++;
label6.Текст = неверный.Метод toString();
проверка 1.Проверено = ложь;
проверка2.Проверено = ложь;
чек-3.Проверено = ложь;
выбирать();
}
если (corect + incorect == 1)
{
Ящик для сообщений.Шоу("тестовый терминал!");
если (corect == 1)
{
UpdateTotalSim(); // здесь я вызываю функцию обновления
Ящик для сообщений.Шоу("Браво!");
}
еще
{
Ящик для сообщений.Шоу("Bleah");
}
этот.Закрывать();
}
}
}
}
поймать (исключение бывший)
{
Ящик для сообщений.Показать(напр.сообщение);
}
}
</pre>

DPaul1994

Я не знаю, имеет ли это значение, но у меня есть еще одна функция, которая выбирает некоторые данные и вызывается в форме загрузки. (использование SQLiteDataReader)

OriginalGriff

Ответ обновлен.
И это может быть - вы закрываете считыватель, команду и соединение, когда вы закончите с ними?

DPaul1994

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

OriginalGriff

"Я должен собрать и сравнить, а затем я должен обновить"
Вот что это делает: адаптер данных считывает всю информацию из БД, а затем возвращает ее как DataTable - DateReader этого не делает: он считывает строку за раз каждый раз, когда вы вызываете метод Read, и база данных "занята" до тех пор, пока читатель и связанная с ним команда не будут закрыты. Вот почему вы получаете ошибку при попытке обновления в вашем цикле - таблица заблокирована кодом цикла.

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

DPaul1994

Omg Smile | :) ) это сработало. Я постараюсь изучить и понять этот способ обновления с помощью DataTable. Спасибо Вам за ваше терпение и желаю всего наилучшего!

OriginalGriff

Всегда пожалуйста!