Editing SQL data - sql

Yeah this is a pretty simple topic, but my form just isn't updating the row in the database:
Here's my code:
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
If Request.QueryString("a") = "edit" Then
Dim CategoryText As String = lstCategory.SelectedItem.Text
Dim conn As New SqlConnection("Data Source=.\SQLEXPRESS; Initial Catalog=LogansArchive; Integrated Security=True;")
Dim cmd As New SqlCommand("UpdateArticle", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#ArticleID", Request.QueryString("i"))
cmd.Parameters.AddWithValue("#Category", CategoryText)
cmd.Parameters.AddWithValue("#ArticleTitle", txtNewTitle.Text)
cmd.Parameters.AddWithValue("#ArticleContent", txtContent.Text)
conn.Open()
cmd.ExecuteNonQuery()
conn.Close()
Else
Dim CategoryText As String = lstCategory.SelectedItem.Text
Dim conn As New SqlConnection("Data Source=.\SQLEXPRESS; Initial Catalog=LogansArchive; Integrated Security=True;")
Dim cmd As New SqlCommand("AddArticle", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#Category", CategoryText)
cmd.Parameters.AddWithValue("#Date", Now)
cmd.Parameters.AddWithValue("#ArticleTitle", txtNewTitle.Text)
cmd.Parameters.AddWithValue("#ArticleContent", txtContent.Text)
conn.Open()
cmd.ExecuteNonQuery()
conn.Close()
End If
End Sub
Here's the SP that the code refers to:
ALTER PROCEDURE [dbo].[UpdateArticle]
-- Add the parameters for the stored procedure here
#ArticleID int,
#Category varchar(20),
#ArticleTitle varchar(100),
#ArticleContent text
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
UPDATE Articles
SET
Articles.Category = (SELECT CategoryID FROM Categories WHERE CategoryName = #Category),
Articles.ArticleTitle = #ArticleTitle,
Articles.ArticleContent = #ArticleContent
WHERE Articles.ArticleID = #ArticleID
END
I've never used nested SELECTs in SQL before so I'm not sure if I did it right.
Aside from that, this is all stuff I've done before so I'm relatively sure that it's all correct.
Finally, there are no errors being reported when I debug, although the updates don't seem to be coming through from the text fields (txtContent.Text isn't changing to reflect the new value).
Thanks in advance for your assistance.
EDIT 1:
Thanks for the updates, I've looked at the CInt(Request.Querystring("i")) issue, and it doesn't solve the problem. I set a breakpoint on the start of the procedure and hovered over txtContent.Text to check the value of it's Text property in the intellisense. Bear in mind that the debugger is still on the first line of the procedure. The txtContent.Text property as shown by the debugger at this point contains none of the changes I made while testing.

Sometimes I find refactoring code to remove duplication can be really helpful in debugging (and long-term maintenance). Here is your code with the duplicated logic centralized a bit. My guess is that your problem is that you are passing a String instead of an Integer to your SP for ArticleID. You'll see that I did a CInt(Request.QueryString("i")) to ensure that you got an integer to work with instead of the string that Request.QueryString("i") returns.
You may also want to look at my TODO comment and put a breakpoint there and use the debugger to make sure that everything you expect made its way into the cmd.Parameters collection.
As far as the stored procedure goes, I don't see anything wrong with it.
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSubmit.Click
Dim categoryText As String = lstCategory.SelectedItem.Text
Dim articleTitle = txtNewTitle.Text
Dim articleContent = txtContent.Text
Dim conn As New SqlConnection("Data Source=.\SQLEXPRESS; Initial Catalog=LogansArchive; Integrated Security=True;")
Dim cmd as SqlCommand
If (Request.QueryString("a") = "edit") Then
Dim articleId = CInt(Request.QueryString("i")) ' Convert provided Article ID to Int
cmd = New SqlCommand("UpdateArticle", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#ArticleID", articleId)
Else
cmd = New SqlCommand("AddArticle", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#Date", Now)
End If
cmd.Parameters.AddWithValue("#Category", categoryText)
cmd.Parameters.AddWithValue("#ArticleTitle", articleTitle)
cmd.Parameters.AddWithValue("#ArticleContent", articleContent)
' TODO: Put a breakpoint here and inspect cmd.Parameters to be sure they all contain what you expect them to contain.
conn.Open()
cmd.ExecuteNonQuery()
conn.Close()
End Sub

Well it's taken 3 months, but I just found the answer.
The reason the debugger doesn't see any changes to my text fields is ... wait for it...
The fields are being populated from the database on page load.
I just had the same problem at work, and one of the other developers hit me with this. To fix the problem, place the code that populates the form into the following IF statement:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
' Populate the form out of the database here
End If
End Sub

Related

How to read date and time from database and compare it to the system date and time

I am working on a project using vb and one of my forms has to display the current active reminders (reminders that haven't hit their deadline yet) into a datagridview and I have another datagridview for reminders that are past the deadline. The date and time along with reminder information is saved into my access database and I want to read the date and time from database and compare it to the system date and time and then display the reminder information.
This is how my form looks like; the top datagridview is for current reminders and the bottom one is for past/out of date reminders:
This the code for my form and what I’ve tried:
Imports System.Data.OleDb
Public Class frmReminderInfo
Private Sub frmReminderInfo_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DisplayCurrentReminders()
End Sub
Private Sub DisplayCurrentReminders()
Dim ReminderDateTime As Date
Dim CurrentDateTime As Date
CurrentDateTime = Date.Now
CurrentDateTime = FormatDateTime(Date.Now, DateFormat.GeneralDate)
ReminderDateTime = FormatDateTime(ReminderDateTime, DateFormat.GeneralDate)
If DbConnect() Then
DgvCurrentReminders.Rows.Clear()
Dim SQLCmd As New OleDbCommand
With SQLCmd
.Connection = cn
.CommandText = "SELECT ReminderDate FROM TblReminder "
Dim rs As OleDbDataReader = .ExecuteReader()
While rs.Read
ReminderDateTime = (rs(0).ToString)
End While
End With
End If
cn.Close()
If CurrentDateTime = ReminderDateTime Then
Dim SQLCmd As New OleDbCommand
With SQLCmd
Dim rs As OleDbDataReader = .ExecuteReader()
While rs.Read
Dim NewStockRow As New DataGridViewRow()
NewStockRow.CreateCells(DgvCurrentReminders)
NewStockRow.SetValues({rs("ReminderID"), rs("CustomerName"), rs("DeviceInfo"), rs("RepairPrice"), rs("ReminderDate")})
NewStockRow.Tag = rs("ReminderID")
DgvCurrentReminders.Rows.Add(NewStockRow)
End While
rs.Close()
End With
End If
cn.Close()
End Sub
End Class
Disposable database objects like Connection should be declared locally in the method where they are used in a Using block.
You don't seem to have any idea of what the parts of an Sql string mean. The Select portion list the fields you want to retrieve. A star (*) in this clause means select all the fields. Here we are using a Where clause to filter the records. Only records where the field ReminderDate is greater than or equal to a parameter will be returned. This will only work if the data has been inserted properly as a DateTime.
The While loop keeps overwriting the value of ReminderDateTime on each iteration so only the last value returned by the reader will remain. Also, you are trying to force a String into a variable declared as a Date. Won't work.
Assuming the code could get beyond If CurrentDateTime = ReminderDateTime Then you would be working with a closed connection. Commands can't execute on a closed connection.
You also don't seem to have an idea how class objects work. Dim SQLCmd As New OleDbCommand Here you declare a new instance of the Command. You have no connection and no CommandText so it can't possibly be executed.
Take a look at the following code until it starts to make sense. Look up what Using blocks do. Look up the Load method of a DataTable to see what it does. Check out what a DataSource property has to offer.
Private Sub frmReminderInfo_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt = GetCurrentReminders()
DgvCurrentReminders.DataSource = dt
End Sub
Private Function GetCurrentReminders() As DataTable
Dim dt As New DataTable
Using cn As New OleDbConnection("Your connection string"),
SQLCmd As New OleDbCommand("SELECT * FROM TblReminder Where ReminderDate >= #Date", cn)
SQLCmd.Parameters.Add("#Date", OleDbType.Date).Value = Now
cn.Open()
Using reader = SQLCmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function

Using block - scope issues

I am learning visual basic and OOP on the fly.
This piece of code displays the query results to a combo box on a form...
Dim c = System.Configuration.ConfigurationManager.ConnectionStrings("db").ToString()
Dim daDogs As New SqlDataAdapter ("select dog_type from humane_society with(nolock)",c)
Dim dtdogs As New DataTable
dadogs.Fill(dtdogs)
cboDogs.DataSource = dtdogs
cboDogs.DisplayMember = "dog_type"
when I change it to use a Using block, the combo box is blank
I think it is a scope issue, but I don't know how to fix it. Any productive suggestions would be greatly appreciated. Thanks!
Dim c = System.Configuration.ConfigurationManager.ConnectionStrings("db").ToString()
Using cDog As New SqlConnection(c)
Using cmd As New SqlCommand("select dog_type from humane_society with(nolock)",cDog)
cmd.CommandType = commandtype.Text
Using daDogs As New SqlDataAdapter(cmd)
Using dtDogs As New Datatable`enter code here`
daDogs.Fill(dtDogs)
' MsgBox(dtMunic.Rows(500).Field(of string)(0))
cboDogs.DataSource = dtDogs
cboDogs.DisplayMember = "dog_type"
End Using
End Using
End Using
End Using
Not sure what that message box is doing in your code. Remember that a message box halts the code until the user responds. You connection, among other things, is open while the code waits.
You are correct that items declared in a block are scoped to that block.
I have separated your database code from your user interface code.
You can save using blocks by adding a comma and combining more than one object in the block. Behaves the same, just makes the code a bit easier to read.
Private ConStr As String = System.Configuration.ConfigurationManager.ConnectionStrings("db").ToString() '"Your connection string"
Private Function GetDogData() As DataTable
Dim dt As New DataTable
Using cDog As New SqlConnection(ConStr),
cmd As New SqlCommand("select dog_type from humane_society with(nolock)", cDog)
cDog.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dtDogs = GetDogData()
cboDogs.DataSource = dtDogs
cboDogs.DisplayMember = "dog_type"
End Sub

In VB.Net, how to repopulate a datagrid from scratch?

I have written a generic VB.net subroutine that populates a datagrid with the results of a query. The subroutine as one parameter, strQuery, which is a string that can translate to any valid SQL-Server view or stored procedure that returns a recordset. Other than that, there is no constraint on the SQL code, and sending two queries that have entirely different field profiles is a valid proposition.
In order to get this to work, I must completely purge the data grid of whatever dataset had been there previously, thus allowing the control to drop its prior identity and start over, allowing, from scratch, the new dateset to redefine the control's contents.
I have finally solved the problem. Perhaps I should have mentioned that I am using Visual Studio 2010, and that if Hersey were using a later version, then the code that worked for him may not have worked for me. The change to my code is one additional line: setting both the name and datapropertyname to the same name. I noticed that when I went to look at the column view, I noticed that the datapropertyname is how the table links to the source, and the name is an effective alias for the field, how it will be presented. Obviously, for clarity sake, both must be the same! This now works as advertised.
Thanks, ~ Peter Ferber
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim con As New SqlConnection("<Enter Connection string here>")
Dim rcd As ADODB.Recordset = ReturnRecordset("Select * From ExcludeWords")
Call DefineDataGrid("Select * From ExcludeWords")
End Sub
Private Sub btnUpdate_Click(sender As System.Object, e As System.EventArgs) Handles btnUpdate.Click
Call DefineDataGrid("Select * From FindWords")
End Sub
Sub DefineDataGrid(ByVal strQuery As String)
Dim con As New SqlConnection("<Enter Connection String Here>")
Dim dt As New DataTable
FindWordGrid.Columns.Clear()
FindWordGrid.DataSource = Nothing
Dim rcd As ADODB.Recordset = ReturnRecordset(strQuery)
Dim MyField As ADODB.Field
Dim iCount As Integer = -1
FindWordGrid.ColumnCount = rcd.Fields.Count
For Each MyField In rcd.Fields
iCount = iCount + 1
FindWordGrid.Columns(iCount).Name = MyField.Name
FindWordGrid.Columns(iCount).DataPropertyName = MyField.Name
Next
Dim cmd As New SqlCommand(strQuery, con)
Dim da = New SqlDataAdapter(cmd)
da.Fill(dt)
FindWordGrid.DataSource = dt
End Sub
Function ReturnRecordset(strQuery As String) As ADODB.Recordset
Dim con As ADODB.Connection = "<Enter Connection string here>"
ReturnRecordset = New ADODB.Recordset
ReturnRecordset.Open(strQuery, con)
End Function
My setup is easy to reproduce: I am using datasets with only a handful of records in each respective table. The only constraint is that the respective runs must have a different field profile. I have been experimenting with different techniques for much of the day, and I now think it best to get some new grey matter on the subject. Getting this process correctly is the last major hurdle for me, in making a key presentation I wish to make, in lobbying for a job role. Thanks, in advance, for your comments, thoughts, and ideas.
Sincerely, ~ Peter Ferber
So, made a couple modifications to the DefineDataGrid code you've posted. Seems to be working for me. I suspect might be something to do with the life cycle of either your cmd or con objects causing your problem. Parsing a number of different number of queries through to it and it rebuilds the datagridview correctly
Sub DefineDataGrid(ByVal strQuery As String)
Dim dt As New DataTable
FindWordGrid.DataSource = Nothing
Using con As New SqlConnection("Your Connection String Here")
Using cmd As New SqlCommand(strQuery, con)
Dim da = New SqlDataAdapter(cmd)
da.Fill(dt)
FindWordGrid.DataSource = dt
End Using
End Using
End Sub
Changed the obvious module level implementations of con and cmd to local variables, and since both types implement IDisposable, wrapped them in a Using pattern

Database not updating new row

Insert new row inside DataGridView
This answer makes it seem like the database should update with the rows.add
Some other sites have instructions, but form a perspective of creating the database from scratch. I already have a database and just want the stupid thing to accept new data.
Here's what I have done:
Private Sub InitializeDataGridView()
Try
' Set up the DataGridView.
With Me.DataGridView1
' Automatically generate the DataGridView columns.
.AutoGenerateColumns = True
' Set up the data source.
'bindingSource1.DataSource = GetData("SELECT * FROM Places and Stuff")
MyTable = GetData("SELECT * FROM Places and Stuff")
'MyDataSet = bindingSource1.DataSource
'MyTable = MyDataSet.Tables(0)
.DataSource = MyTable
' Automatically resize the visible rows.
.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders
' Set the DataGridView control's border.
.BorderStyle = BorderStyle.Fixed3D
' Put the cells in edit mode when user enters them.
.EditMode = DataGridViewEditMode.EditOnEnter
' Disables Add New Row
.AllowUserToAddRows = False
End With
Catch ex As SqlException
MessageBox.Show(ex.ToString, _
"ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
System.Threading.Thread.CurrentThread.Abort()
End Try
End Sub
I am binding the DGV to a table. It seems like maybe I need a dataset somewhere to update but I cannot figure out how to populate a dataset with a table that is also a sql database. You can also see where I have played around with other datasets/datatables etc.
I also got my datagridview to add a row but the database is being lazy:
Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
'Determine Last Row Index
Dim dgvrowCnt As Integer = DataGridView1.Rows.Count - 1
If DataGridView1.Rows.Count > 0 Then
Dim myRow As DataRow = MyTable.NewRow
myRow(0) = DataGridView1.Rows(dgvrowCnt).Cells(0).Value + 1
MyTable.Rows.Add(myRow)
Else
Dim myRow As DataRow = MyTable.NewRow
myRow(0) = 230
MyTable.Rows.Add(myRow)
End If
End Sub
I am a little saddened by not being able to use myRow("<column name here>") = 230 but I'll have to get over it I guess.
I have tried refreshing and checking the table to see if my form needs to be refreshed, but that doesn't seem to be the case.
This page http://support.microsoft.com/kb/301248 has 2 lines and claims it does what I am hoping for:
Dim objCommandBuilder As New SwlCammandBuilder(daAuthors)
daAuthors.Update(dsPubs, "Authors")
I cannot get my table into a dataset as shown in the binding lines of my example.
It seems that you haven't understood a fundamental concept of ADO.NET. The DataTable and other objects like the DataSet are 'disconnected' objects, meaning that adding/updating and removing rows doesn't update/insert/delete the database table.
You need to create an SqlCommand, prepare its command text and then Execute a query to update your db (other methods include using an SqlDataAdapter and its Update method)
For example, to insert a single row in a datatable your code should be something like this
Using con = New SqlConnection(.....constringhere...)
Using cmd = new SqlCommand("INSERT INTO table1 (field1) values (#valueForField)", con)
con.Open()
cmd.Parameters.AddWithValue("#valueForField", newValue)
cmd.ExecuteNonQuery()
End Using
End Using
A more complete tutorial could be found here
Instead this could be a pseudocode to use a SqlDataAdapter and a SqlCommandBuilder to automate the construction of the commands required to store your changes back to the database
' Keep the dataset and the adapter at the global class level'
Dim da As SqlDataAdapter = Nothing
Dim ds As DataSet
Private Function GetData(ByVal sqlCommand As String) As DataSet
ds As New DataSet()
Dim connectionString As String = "Data Source=...."
Using con = New SqlConnection(connectionString)
conn.Open()
Using command = New SqlCommand(sqlCommand, con)
Using da = New SqlDataAdapter(command)
da.Fill(ds)
End Using
End Using
End Using
Return ds
End Function
Use the first table inside the DataSet returned by GetData as Datasource of the grid (or just use the whole dataset)
.DataSource = GetData(.......).Tables(0)
' Add a new button to submit changes back to the database'
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
Dim builder = New SqlCommandBuilder(da)
da.UpdateCommand = builder.GetUpdateCommand()
da.InsertCommand = builder.GetInsertCommand()
da.DeleteCommand = builder.GetDeleteCommand()
da.Update(ds)
End Sub
Please, note that I cannot test this code, and I offer it as a pseudocode without any error checking required by a more robust application.

Database will read but will not write

I have a problem where I am unable to make a booking to a Sql server .mdf database, but I am able to read to it.
No error messages occur and I have tried everything I can think of. Any help will be highly appreciated and thanks in advance!
Here is the code used for the insert into command:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim SQLCode As New SQLCode
Dim con As New SqlConnection
Dim cmd As New SqlCommand
Dim lrd As SqlDataReader
Dim inscmd As New SqlCommand
cmd.Parameters.AddWithValue("#StaffInitials", lblStaffInitials.Text.Trim())
lblStaffInitials.Text = lblStaffInitials.Text
cmd.Parameters.AddWithValue("#Week", lblWeek.Text.Trim)
lblWeek.Text = lblWeek.Text
cmd.Parameters.AddWithValue("#Period", (lblPeriod.Text.Trim))
lblPeriod.Text = lblPeriod.Text
cmd.Parameters.AddWithValue("#Day", lblDay.Text.Trim)
lblDay.Text = lblDay.Text
cmd.Parameters.AddWithValue("#Subject", lblSubject.Text.Trim)
lblSubject.Text = lblSubject.Text
cmd.Parameters.AddWithValue("#YearGroup", lblYear.Text.Trim)
lblYear.Text = lblYear.Text
cmd.Parameters.AddWithValue("#NumberOfPupils", (lblNoOfPupils.Text.Trim))
lblNoOfPupils.Text = lblNoOfPupils.Text
cmd.Parameters.AddWithValue("#ControlledAssesment", lblControlledAssesment.Text.Trim)
lblControlledAssesment.Text = lblControlledAssesment.Text
cmd.Parameters.AddWithValue("#Room", lblRoom.Text.Trim)
lblRoom.Text = lblRoom.Text
cmd.Parameters.AddWithValue("#Session", txtSession.Text.Trim)
txtSession.Text = txtSession.Text
con.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("RoomBookingSystem.My.MySettings.Database1ConnectionString1").ConnectionString
Try
Using cn As New SqlConnection(con.ConnectionString)
con.Open()
inscmd.CommandText = "INSERT INTO Booking (Week, Day, Period, Subject, YearGroup, StaffInitials,NumberOfPupils,Session,Room,ControlledAssesment) VALUES (#Week,#Day,#Period,#Subject,#YearGroup,#StaffInitials, #NumberOfPupils,#Session,#Room,#ControlledAssesment)"
inscmd.Connection = con
inscmd.ExecuteNonQuery()
inscmd.Parameters.Clear()
End Using
Finally
con.Close()
End Try
MsgBox("Your Booking Has Been Made Successfully")
Clicky = False
MainViewForm.btnBackToBooking.Visible = False
FormView.Show()
Me.Hide()
End Sub
As far as I can tell the problem lies within the databases location.
When the program is debugged a copy of your database is placed within the bin/debug folder, if you look in here you will see the copy and your code will right to this database and Not The original Database (if you click show all files then go to the bin/debug file and then open with database explorer you can see the data imputed on the last debug/running)
To fix this you need to do the following:
Your connection string
con.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("RoomBookingSystem.My.MySettings.Database1ConnectionString1").ConnectionString
Will connect to the database within the bin folder mentioned previously.
You need to go into your app.config file find the specific location for your database and use this for you connection string, this will allow you to insert/update data from the non copy of the database.
You have two different Sql Commands when only one SqlCommand is needed. Add the parameters to inscmd rather than cmd.
So simply remove this line :
Dim cmd As New SqlCommand
and do this for the rest :
inscmd.Parameters.AddWithValue("#StaffInitials", lblStaffInitials.Text.Trim())
.....
.....
Another thing to note, you don't need this :
Using cn As New SqlConnection(con.ConnectionString)
Change your code like this :
Try
con.Open()
inscmd.CommandText = "INSERT INTO Booking (Week, Day, Period, Subject, YearGroup, StaffInitials,NumberOfPupils,Session,Room,ControlledAssesment) VALUES (#Week,#Day,#Period,#Subject,#YearGroup,#StaffInitials, #NumberOfPupils,#Session,#Room,#ControlledAssesment)"
inscmd.Connection = con
inscmd.ExecuteNonQuery()
inscmd.Parameters.Clear()
Catch ex As Exception
// use message box to read the error (if there is any). or simply read the
// ex.Message in debuggin mode.
Finally
con.Close()
End Try
and by the way I don't see where you are setting this property con.ConnectionString. where is your connection string?