I have a question similar to this one, but reading the (accepted) answer didn't give me much insight, so I'm hoping to state it more clearly and get a clearer response back.
I'm attempting to insert a data row into a table. I'm using TableAdapter's custom "insert nonQuery" that I wrote (it works, I tested) to accept some parameters. I'm fairly new to this business of communication with a database via .NET and what I'm doing is probably wrong by design. My questions are why is it wrong and what's the right way to do it? Both are equally important, IMO.
Here's some sample VB code I wrote:
Dim arraysTableAdapter As New UnitTestsDataSetTableAdapters.ArraysTableAdapter
Try
arraysTableAdapter.InsertArray("Test Array", 2, 1, 2, "Test user")
Catch ex As SqlException
MsgBox("Error occured when trying to add new array." _
& vbNewLine & vbNewLine _
& ex.Message)
End Try
...and that's pretty much it. There is no exception raised, my table does not get a new row inserted. Everything is just the way it was before I called the InsertArray method. When I test my query in the QueryBuilder with the same parameters, a new row gets added to the database.
Now, I do understand some of the reasons this would not work. I understand that I need to create and select a row in my DataSet (no idea how to do it) in order to tell the TableAdapter what it's adding the data to. Or at least I got that impression from reading the vast abyss of forums.
I would really like to use TableAdapter at some point, because it knows that .InsertArray exists and it knows which parameters it likes. I could try and do it using
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con.ConnectionString = connString
con.Open()
cmd.CommandText = "INSERT ...... all that jazz"
but it's not nearly clean enough for how clean I like my code to be. So, is there any way to do what I'm trying to do the way I'm doing it? In other words, how do I use the neat structure of a TableAdapter to communicate to my DataSet and put a new row in it?
Thanks in advance!
There were two things that were wrong:
(minor issue) I did not have a DataTable filled from the TableAdapter (see code below)
(major, sneaky issue) My method worked from the very beginning. There is nothing extra to be added except for the line above. However, the ConnectionString of arraysTableAdapter was pointing my program (automatically, by default) to a wrong location. Once I manually set the ConnectionString, it worked perfectly.
Here's my complete code:
Dim connString As String = "Some correct connection string"
Dim arraysDataTable As New SpeakerTestsDataSet.ArraysDataTable
Dim arraysTableAdapter As New UnitTestsDataSetTableAdapters.ArraysTableAdapter
'Set the correct connection string'
arraysTableAdapter.Connection.ConnectionString = conn
'Fill table from the adapter'
arraysTableAdapter.Fill(arraysDataTable)
Try
arraysTableAdapter.Insert("Test", 2, 1, 2, Now, Now, "Me")
Catch ex As Exception
MsgBox("Error occured when trying to add new array." _
& vbNewLine & vbNewLine _
& ex.Message)
End Try
The accepted answer in the question you linked to is correct, but sometimes saying it in different words helps:
A TableAdapter is used to communicate between a DataTable (there can be one or more DataTables in a DataSet) and a database. It can pull data from a database and add it to a DataTable and it can send data from a DataTable to the database. It's purpose is to create and execute the SQL code required to make this communication work.
You are trying to use the TableAdapter to directly add data to your DataTable. This will not work. Instead, you should use the methods that come with the DataTable to add a new row to the DataTable and then (if necessary) use your TableAdapter to send that row to a database.
For instance, with a Dataset called DataSet1 that contains a DataTable called DataTable1 that has three text columns you can add a record like this:
Dim d As New DataSet1
d.DataTable1.AddDataTable1Row("value1", "value2", "value3")
That AddDataTable1Row method is automatically created for you, and I think is what you are looking for.
Related
I'm develop an application using forms in vb.net with visual studio 2019
I have code in the event click for one button
Dim oda As New OleDbDataAdapter
Dim ods As New DataSet
Dim consulta As String
Dim cadena As New OleDbConnection
Dim comando As New OleDbCommand
Try
cadena.Open()
comando = New OleDbCommand("Insert into QRQC (Nombre,NumControl,Fecha,Hora,Turno)" &
"values(txt_nombre,txt_numControl,lbl_fecha,lbl_hora,cBox_turno)", cadena)
consulta = "Select *From QRQC"
oda = New OleDbDataAdapter(consulta, cadena)
ods.Tables.Add("QRQC")
oda.Fill(ods.Tables("QRQC"))
Dim row As Integer
row = ods.Tables("QRQC").Rows.Count - 1
courrentId = ods.Tables("QRQC")(row)("ID_QRQC").ToString()
frm_newPt2.lbl_folioQRQC.Text = courrentId
cadena.Close()
Catch ex As Exception
MsgBox("Error al generar el registro en la base de datos", vbCritical, "Aviso")
Console.WriteLine(ex)
cadena.Close()
GoTo skip
End Try
Everything goes perfectly, but when I delete some record on my DB this part of the code always return the value 102
courrentId = ods.Tables("QRQC")(row)("ID_QRQC").ToString()
How can i solve this problem?
First of all, your insert command is wrong, and will not work.
You have "values(txt_nombre. etc etc."
But that is just a string and NOT the actual values from the form. So you are actually going to "instert txt_nombre" into that table and NOT the value of that label or text box on the form!!!
So you need to fix and get your insert command working FIRST.
And if this is just editing data then consider using the data binder, since navigation, editing, deleting and saving of data to/from the table can occur 100% automatic whiteout ANY code on your part.
so first up is to fix that insert command. You can't JUST use a string with the names of the controls else that would actually as noted try to insert the names of the controls as text and NOT the values of the controls.
And lets clean up a few other things. No need for a dataset, since a dataset is a SET of tables - we only dealing with one table (so use a data table).
But as noted, before we mess with data tables, we have to fix that insert command.
It will, can look like this:
Dim strSQL As String
strSQL = "Insert into QRQC (Nombre,NumControl,Fecha,Hora,Turno) " &
"VALUES(#nombre,#numControl,#fecha,#hora,#turno)"
Using cmdSQL As New OleDbCommand(strSQL,
New OleDbConnection(My.Settings.TestDB))
cmdSQL.Parameters.Add("#nombre", OleDbType.Integer).Value = txt_nombre.Text
cmdSQL.Parameters.Add("#numControl", OleDbType.Integer).Value = txt_numControl.Text
cmdSQL.Parameters.Add("#fecha", OleDbType.Integer).Value = lbl_fecha.Text
cmdSQL.Parameters.Add("#hora", OleDbType.Integer).Value = lbl_hora.Text
cmdSQL.Parameters.Add("#turno", OleDbType.Integer).Value = txt_nombre.Text
cmdSQL.Connection.Open()
cmdSQL.ExecuteNonQuery()
End Using
So you have to "replace" the string values in the sql with the ACTUAL values you are using.
You also don't show where/how you setup your connection to the database. I guessed that you used the applications settings and the connection builder - so you have to change TestDB to your actual connection that you used.
The above will thus get your insert command working.
At that point, you can post a new question in that after you do a insert, how to get the new autonumber primary key, or whatever else you wanted to do, but your insert statement as written will not work.
As noted, perhaps it better to use data bound controls. This will result in a Access like design experience, and you not having to write ANY code to edit a table in vb.net.
And it not clear if the control names I used are correct (or they are even controls on the form), but if they are, then ".Text" is required to grab the values. You have to of course change (check) that the control names I used and guessed are correct.
You also have to change the data type "integer" I used in above to the correct data types. For text I recommend you use .VarWChar
I'm making a WinForms application using VB.NET. I have a DataGridView that I am using to display results of a query to an SQL-Server Database. This works fine:
Dim SQL As New SqlConnection()
Dim CMD As New SqlCommand()
Dim ADP As New SqlDataAdapter()
Dim TBL As New DataTable()
SQL.Close()
SQL.ConnectionString = "Server=" & GetServerIP() & ";Database=" & GetDB() & ";User Id=" & userID & ";Password=" & pass & ";"
CMD.Connection = SQL
CMD.CommandText = "SELECT * FROM " & table
SQL.Open()
ADP.SelectCommand = CMD
TBL.Clear()
ADP.Fill(TBL)
DataGridView1.DataSource = TBL
The issue is that the DataGridView has a column NAME which is empty in every row.
I tried changing the query to SELECT SEQ_NUM FROM CONFIG_SYS that resulted in a DataGridView with a NAME and SEQ_NUM column. I tried calling DataGridView1.Columns.Clear() before the DataGridView1.DataSource = TBL and that does not have an effect on anything. I should mention that if I query any table in my database that does not have a NAME column, I get the same results with an empty NAME column in my DataGridView.
My theory is that a DataGridView automatically adds NAME as the first column, expecting the Database Table to be set up with a NAME column as the primary key. However, my table does not have NAME, it has a column called SEQ_NUM as the primary key. I am able to work around this by doing DataGridView1.Columns("NAME").Visible = False but I don't feel that this is the best way to do it.
Is there a better way to handle this - I'd like the column to not exist at all in the data grid, not just not be visible.
What was causing my issue was the fact that I was calling TBL.Clear() incorrectly.
Calling DataTable.Clear() will clear the Data from a DataTable but it will leave the columns in place.
Instead I should have been calling TBL.Columns.Clear(), which gets rid of the columns of the DataTable. However, using Breakpoints and Visual Studio's DataTable Visualizer I noticed that only calling TBL.Columns.Clear() left the empty rows still in the DataTable. Therefore, to answer the question of how to get rid of a column in a DataGridView that you don't know why/how is there, I suggest to call:
DataTable.Clear()
DataTable.Columns.Clear()
Before setting your DataGridView equal to your DataTable.
Taken from the MSDN:
The .Clear() Method of a DataTable Class "clears the DataTable of all data."
The DataTable.Columns Property gets "a DataColumnCollection that contains the collection of DataColumn objects for the table"
The DataColumnCollection Class also has a .Clear() Method which "clears the collection of any columns."
Thank you #TnTinMn for pointing me in the right direction by using breakpoints and #LarsTech for making me realize that I harshly mixed up DataGridView and DataTable in my original answer.
I hope this post can help others prevent themselves from ripping their hair out about where a non-existent column in their databases seemingly materialized from... If this does not fix your specific issue. I would also check the Query, Database Table setup, and the DataGridView; but for me the issue was with the DataTable.
I would really appreciate any help I can get.
My problem is that I have Combobox1 bound to a BindingSource and the DataMember and ValueMember property linked and working. For the life of me I do not know how to use the value (selected valuemember) of Combobox1 to filter the results I show on Combobox2. I am desperate for a simple way to do this.
my failing code is below
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim conn As New SqlConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\Database1.mdb") 'This line fails
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember & "'"
Dim da As New SqlDataAdapter(strSQL, conn)
Dim ds As New DataSet
da.Fill(ds, "Disk")
With ComboBox2 'Here i try to populate the combobox2
.DataSource = ds.Tables("Questions")
.DisplayMember = "Question_String"
.ValueMember = "Question_Code"
.SelectedIndex = 0
End With
End Sub
I keep getting a system level error as follows
{"Keyword not supported: 'provider'."}
I have tried a few other options but the errors I get seem more cryptic can someone please help me on this. I will appreciate it a lot.
Dim conn As New OleDBConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source='|DataDirectory|\Database1.mdb'")
Also your query has to use a string not an object so try...
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
Because you are using a Provider for a connection that doesn't need it because the provider should be an SQL driver.
I don't know what database you are using (well, the file is an access file), but you need to check you have the correct connection string
see http://www.connectionstrings.com/sql-server-2008#p2
Here are a couple of observations about your code that I hope you find helpful:
First, you might want to look at this MSDN help on how to move your database connection string out of the code and into a configuration file. This is especially important for your code to work to work more seemlessly across different environment (dev box, staging, production, etc) - Connection Strings and Configuration Files (ADO.NET)
I also noticed that you never explicitly open or close the connection. Per this entry on stack overflow, you should be ok, but keep in mind that if you happen to change the code to explicitly open the connection you will also need to close it.
I also noticed that you aren't using a parameterized query. This makes your code vulnerable to a SQL Injection attack. Here is a link to a blog posting by Scott Guthrie 'Tip/Trick: Guard Against SQL Injection Attacks'. You never know who may copy and paste your block of code with this bad practice.
Finally, you do the following query (with appropriate mods from other answers:
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
And subsequently only use Question_String, and Question_Code in your code. You might want to consider changing your query to only pull the columns you need. This is especially helpful when you have tables with many columns. Otherwise you will needlessly pull data your code never actually needs. So your query would become:
Dim strSQL As String = "SELECT Question_String, Question_Code FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
I'm a bit puzzled here. I did a form containing a simple datagridview containing data from an MDB file. The connection was alltogether done by Visual Studios wizard so alot of stuff was created automatically. Then I databinded the textboxes to each column in the database and managed to update the database via my own command buttons such as "Update" with this code:
Me.MainTableBindingSource.EndEdit()
Me.MainTableTableAdapter.Update(Me.DBDataSet.MainTable)
Me.DBDataSet.MainTable.AcceptChanges()
This doesn't seem to work with sql. At this point, I've done everything from scratch in this order, added a datagridview and added a database connection with the wizard when connecting the datagridview to a database. Only this time around I created an SQL connection instead.
And Visual Studio created "MainTableTableAdapter", "DBDataSet", "DBDataSet.MainTable".
The SQL server is something which was installed automatically when installing Visual Studio and it does seem to work after creating the table adapter and dataset if there's data in it. In some time I plan to use an SQL Server on the internet which hosts the dataset. So I want to be able to easily edit the source.
The only thing missing now is how to add a row, delete selected row and editing selected row via my own textboxes. More like a fill-in form. Any ideas to put me in the right direction? I've tried googling it and I've found some stuff, but most of it contains stuff on how to create the datasets and etc. And I'm not sure what Visual Studio has done automatically. And I want to update everything just as easily as I did with these three lines of code when I used a local MDB file.
If it's SQL you can do something like this. Here's an example delete function:
Public Shared Function DeleteStuff(ByVal id As Integer) As Integer
Dim query As String = _
"DELETE FROM tbl_Stuff " & _
"WHERE ID_Stuff = " & id & ";"
Dim connection As SqlConnection = YourDB.GetConnection
Dim deleteCommand As New SqlCommand(query, connection)
Dim rowCount As Integer = 0
Try
connection.Open()
rowCount = deleteCommand.ExecuteNonQuery()
Catch ex As SqlException
Throw ex
Finally
connection.Close()
End Try
Return rowCount
End Function
There may be better ways, but you can always pass in SQL queries.
EDIT: Sorry this is more than three lines of code. ;)
OK - I have worded this search 40 different ways and I seem to be lost here.
Every example I find seems so happy that you can easily drag and drop a datagrid and let the user fill it in -- then they stop!
I know how to do everything I am asking through LINQ. That obviously won't translate here. I really should have learned ADO.NET first, then LINQ, but NOoooo...
I need to know how to do the following in .NETCF (Windows Mobile 5) using a SQL CE database on the device.
Add a new record and populate some or all of the fields with data I supply. I don't need to add a record to a datagrid - sometimes the user will not even see the record. How do I add a new record -- put data into it and save it?
For example: Create a new delivery record, say, and have the program store the date in one field and a number in another field.
Search for a record, then update data in it.
Again, using LINQ I can do this easily -- I cannot for the life of me find any examples of doing it without it.
I can find lots of examples of populating a grid of databound fields, letting the user make changes then saving it out. I don't need to do that.
Say I need to search for the one record that meets a criteria (customerID=10 and orderID=1234), then when (if) that record is found, update a field in it.
Please let me know if you need any more info. I have done a lot of reading and just seem to be missing something!
Thanks in advance...
For #1, there are a few ways. Two easy, common ways are:
Use a SqlCeResultset, and create a row with it, then insert.
using(SqlCeConnection connection = new SqlCeConnection(myConnString))
using (SqlCeCommand cmd = new SqlCeCommand())
{
connection.Open();
cmd.CommandText = "MyTable";
cmd.CommandType = CommandType.TableDirect;
cmd.Connection = Connection;
SqlCeResultSet rs = cmd.ExecuteResultSet(ResultSetOptions.Updatable);
SqlCeUpdatableRecord record = rs.CreateRecord();
// do something to set your values in the record
rs.Insert(record);
}
Use a SqlCeCommand, set the command SQL and call ExecuteNonQuery.
using (SqlCeConnection connection = new SqlCeConnection(myConnString))
using (SqlCeCommand cmd = new SqlCeCommand())
{
connection.Open();
cmd.CommandText = "INSERT INTO MyTable(Foo) VALUES('bar')";
cmd.CommandType = CommandType.Text;
cmd.Connection = Connection;
cmd.ExecuteNonQuery();
}
For #2 it's not much different. Use an updateable resultset, seek to the record, modify and call Update or build your SQL and send it through the command using ExecuteScalar or ExecutNonQuery. The code is similar enough to those above that I'll leave it to you to work out.
A quick search on "SqlCeResultSet" and "example" or "update example" give loads of relevant results.
Also for anybody else searching this book also has a really good chapter on this procudere:
http://my.safaribooksonline.com/0321174046
I am still working my through this issue but making good progress,
Thanks for the help.
Thank you,
Between that and this code here, I think I am on my way.
Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click
Dim con As SqlCeConnection
con = New SqlCeConnection(("Data Source = " & Me.NorthwindDatabaseFullPath))
con.Open()
Dim sqlcdm As String = "INSERT INTO Orders VALUES(999, 'ALFKI', 1, 'RUDEDOG', '', '', '', '', '', 2, '11/15/1967', '11/16/1967', '11/17/1967', '23')"
Dim SqlCeCommand As New SqlCeCommand(sqlcdm, con)
SqlCeCommand.ExecuteNonQuery()
End Sub