2016-08-04 3 views
1

Ошибка в базе данных заблокирована даже после того, как я установил все команды. Я пытаюсь записать в базу данных, и он не работает в команде INSERT внизу. Раньше я работал, но по какой-то причине он начал терпеть неудачу.База данных заблокирована даже после удаления всех команд

Sub Btn_SubmitClick(sender As Object, e As EventArgs) 

    If MsgBox("Are you sure?",vbYesNo,"Submit?") = 7 Then 
     'returns to previous screen 
    Else 
     'commences insert into database 

     Rows = (dataGridView1.RowCount - 1) 

     While count < rows 

      'putting grid stuff into variables 
      DateStart = dataGridView1.Rows(Count).Cells(0).Value.ToString 
      DateEnd = dataGridView1.Rows(Count).Cells(2).Value.ToString 'note other way round 
      TimeStart = dataGridView1.Rows(Count).Cells(1).Value.ToString 
      TimeEnd = dataGridView1.Rows(Count).Cells(3).Value.ToString 
      TotalHours = dataGridView1.Rows(Count).Cells(4).Value.ToString 
      OccuranceNo = dataGridView1.Rows(Count).Cells(5).Value.ToString 

      'fetching reason ID for Storage 

      SQLcommand = SQLconnect.CreateCommand 

      SQLcommand.CommandText = "SELECT Reason_ID FROM Reasons WHERE Reason_Name = '" & dataGridView1.Rows(Count).Cells(6).Value.ToString & "'" 

      SQLreader = SQLcommand.ExecuteReader 

      ReasonID = SQLreader("Reason_ID") 

      SQLcommand.Dispose 

      'fetching site ID for storage 
      SQLcommand = SQLconnect.CreateCommand 

      SQLcommand.CommandText = "SELECT Site_ID FROM Sites WHERE Site_Name = '" & dataGridView1.Rows(Count).Cells(7).Value.ToString & "'" 

      SQLreader = SQLcommand.ExecuteReader 

      SiteID = SQLreader("Site_ID") 

      SQLcommand.Dispose 

      Oncall = dataGridView1.Rows(Count).Cells(8).Value.ToString 

      'increment counter 
      Count = Count + 1 

      'send to database 

      SQLcommand = SQLconnect.CreateCommand 

      SQLcommand.CommandText = "INSERT INTO Shifts (Staff_ID, Date_Shift_Start, Date_Shift_End, Time_Shift_Start, Time_Shift_End, Total_Hours, Occurance_No, Site_ID, On_Call_Req, Rate, Approved, Reason_ID) VALUES ('" & userID & "' , '" & DateStart &"' , '" & DateEnd & "' , '" & TimeStart & "' , '" & TimeEnd & "' , '" & TotalHours & "' , '" & OccuranceNo & "' , '" & SiteID & "' , '" & Oncall & "' , '"& "1" & "' , '" & "N" & "' , '" & ReasonID & "')"   
      SQLcommand.ExecuteNonQuery() 

      SQLcommand.Dispose 

     End While 



     MsgBox("Ok") 
    End If 
End Sub 
+0

Просто попробовал это, и он возвращает ошибку при компиляции, говоря, что он не является членом команды SQL:/ –

+1

Вы должны использовать SQL-параметры, а не строку concat для SQL. Это особенно важно при использовании SQLIte, который является беспричинным. Если у вас нет проверочных ограничений для каждого столбца, вы можете легко вытолкнуть строки в целые столбцы. если вы займете 15 минут, чтобы узнать, как использовать DataAdapter, который может быть заменен на 1 строку кода. – Plutonix

+0

Я также предлагаю вам использовать предложения 'Using', чтобы он автоматически удалял объекты в' End Using'. Когда вы переходите к нему, оно дает заблокированное сообщение при первой вставке, все вставки, случайные ??? Не случайно также использовать другую программу для просмотра/изменения содержимого базы данных? Любая вероятность, что файл был установлен только для чтения? – topshot

ответ

2

Есть несколько вещей, которые должны быть изменены в показанном коде. Поскольку ни один из объектов Connection, Command или Reader не объявлен в коде, они должны быть глобальными объектами, которые вы повторно используете. Не делайте этого.

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

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

Dim SQL = "INSERT INTO Sample (Fish, Bird, Color, Value, Price) VALUES (@f, @b, @c, @v, @p)" 

Using dbcon As New SQLiteConnection(LiteConnStr) 
    Using cmd As New SQLiteCommand(SQL, dbcon) 

     dbcon.Open() 
     cmd.Parameters.Add("@f", DbType.String) 
     cmd.Parameters.Add("@b", DbType.String) 
     cmd.Parameters.Add("@c", DbType.String) 
     cmd.Parameters.Add("@v", DbType.Int32) 
     cmd.Parameters.Add("@p", DbType.Double) 

     Dim fishName As String 
     For Each dgvR As DataGridViewRow In dgv2.Rows 

      ' skip the NewRow, it has no data 
      If dgvR.IsNewRow Then Continue For 

      ' look up from another table 
      ' just to shorten the code 
      userText = dgvR.Cells(0).Value.ToString() 
      fishName = dtFish.AsEnumerable(). 
           FirstOrDefault(Function(f) f.Field(Of String)("Code") = userText). 
           Field(Of String)("Fish") 
      ' or 
      'Dim drs = dtFish.Select(String.Format("Code = '{0}'", userText)) 
      'fishName = drs(0)("Fish").ToString() 

      cmd.Parameters("@f").Value = fishName 
      cmd.Parameters("@b").Value = dgvR.Cells(1).Value 
      cmd.Parameters("@c").Value = dgvR.Cells(2).Value 
      cmd.Parameters("@v").Value = dgvR.Cells(3).Value 
      cmd.Parameters("@p").Value = dgvR.Cells(4).Value 

      cmd.ExecuteNonQuery() 
     Next 
    End Using 
End Using 
  • Примечание: Как и в исходном коде нет проверки данных - то есть, он предполагает, что все, что они ввели всегда справедливо. Это редко бывает хорошим предположением.
  • В коде реализованы Using блоки, которые будут объявлять и создавать целевые объекты (dbCommands, connections) и удалять их по завершении с ними. Они не могут мешать коду в другом месте, потому что они существуют только в этом блоке.
  • SQL-параметры используются для упрощения кода и определения типов данных. Побочным эффектом конкатенирования SQL как вы, является то, что все передано как строка! Это может быть очень плохо с SQLite, который является безликим.
  • Я бы не стрелял из нескольких поисковых запросов в цикле. Исходный код должен забрасывать InvalidOperationException, так как он никогда не Read s с DataReader.
    • Возможно, лучший способ сделать это было бы для Sites и Reasons быть ComboBox столбца в DGV, где пользователь видит любой текст, а ValueMember уже будет доступен для кода для хранения.
    • Еще одна альтернатива, указанная в ответе, заключается в предварительной загрузке данных DataTable с данными и последующем использовании некоторых методов расширения для поиска необходимого значения.
    • Если вы «должны» использовать читателей, реализуйте их в своих собственных блоках Using.
  • Используется цикл For Each, который обеспечивает проверку фактической строки.
  • Я бы серьезно пересмотрел идею хранения чего-то вроде startDateTime как отдельных Date и Time полей.

Это основы при использовании объектов поставщика БД. Не исключено, что рефакторинг, показанный в этой процедуре, устранит что-нибудь, потому что проблема может быть в любом месте кода в результате того, что объекты DBProvider остаются открытыми и не удаляются.

Еще одна вещь, которую нужно проверить, - это любой менеджер пользовательского интерфейса, который вы можете использовать для db. Многие из них накапливают изменения до тех пор, пока вы не нажмете кнопку «Сохранить или записать». В то же время некоторые блокируют БД.

Наконец, даже если код здесь короче и проще, используя DataAdapter и DataTable позволит новым данным в DGV для автоматически обновления базы данных:

rowsAffected = myDA.Update(myDT) 

Это займет, возможно, 30 минут чтобы узнать, как настроить его таким образом.