I am attempting to make a small application allowing users to read the content of a table describing the inventory of a warehouse, search depending on 2 rows indicating which warehouse the item resides in and by it's assigned barcode which i already managed to get to work by using a binding source, and a datagrid view, updating the view trough a query taking the barcode and location as strings from two boxes.
The second part i would need for this application to suit my basic objective would be to have a way to add new lines and store them into the original table on the database so users could add the new items independently from the warehouses directly.
So far i have encountered 2 issues: i need a primary key that would represent a sequential ID but i do not know how to produce a sequentially incrementing ID, i manage to get the first addition ID by using a top 1 order by desc query combination but the data does not get updated after adding the new line, producing an error since it tries to add another line with the same value for the primary key.
The second issue i am encountering is: the gridview gets altered accordingly to the data i input in the textboxes i set up to gather the various values for the table but the table on the database itself is not showing any change, keeping only the test data i inputted at it's creation.
Public Class AddItems
Private Sub AddItems_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'MagazzinoDataSet.LastUsedID' table. You can move, or remove it, as needed.
Me.LastUsedIDTableAdapter.LastUsedID(Me.MagazzinoDataSet.LastUsedID)
'TODO: This line of code loads data into the 'MagazzinoDataSet.Stock' table. You can move, or remove it, as needed.
Me.StockTableAdapter.Fill(Me.MagazzinoDataSet.Stock)
'TODO: This line of code loads data into the 'MagazzinoDataSet.AddWarehouseList' table. You can move, or remove it, as needed.
Me.AddWarehouseListTableAdapter.AddWarehouseList(Me.MagazzinoDataSet.AddWarehouseList)
'TODO: This line of code loads data into the 'MagazzinoDataSet.WarehouseList' table. You can move, or remove it, as needed.
Me.WarehouseListTableAdapter.Fill(Me.MagazzinoDataSet.WarehouseList)
'TODO: This line of code loads data into the 'MagazzinoDataSet.Stock' table. You can move, or remove it, as needed.
Me.StockTableAdapter.Fill(Me.MagazzinoDataSet.Stock)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim R As DataRow = MagazzinoDataSet.Tables("Stock").NewRow()
R("Supplier") = Supplier.Text
R("Producer_code") = ProducerCode.Text
R("Barcode") = Barcode.Text
R("Comp_name") = ComponentName.Text
R("Warehouse") = Warehouse.Text
R("Internal_Code") = InternalCode.Text
R("Description_IT") = ITDescr.Text
R("Description_EN") = ENDescr.Text
'R("ID") = NextID.SelectedValue <- this would be an hidden uneditable multibox containing the product of the query finding the next value to be inserted in the table (basically last ID + 1, nothing fancy)"ID" would be the primary key of this table
R("Quantity") = "0"
MagazzinoDataSet.Tables("Stock").Rows.Add(R)
DataGridView1.DataSource = MagazzinoDataSet.Stock
End Sub
End Class
To sum it up:
How would i go about updating the database table to include the new line?
Is there a smart way to find the last value, incrementing it by 1 to have the next value and updating it when inserting a new line, so as to not end up with 2 lines with the same value for primary key, generating an error?
To set an incremental ID in the Db, assuming you have access to SQL Server Management Studio, in Design of the table, for the ID column, in Column Properties, scroll down to Identity Specification and set (is Identity) to Yes.
To add a new row, I use this code:
Using NotesDS As New DataSet
Using NotesDA As New SqlDataAdapter With {.SelectCommand = New SqlCommand With {.Connection = SQLDBConnection, .CommandText = "SELECT * FROM Notes WHERE ID = " & ID}}
NotesDA.Fill(NotesDS, "Notes")
Using NotesDV As New DataView(NotesDS.Tables("Notes"))
Using NoteBuilder As New SqlCommandBuilder(NotesDA) With {.QuotePrefix = "[", .QuoteSuffix = "]"}
If NotesDV.Count = 0 Then
Dim NoteDRV As DataRowView = NotesDV.AddNew
NoteDRV.Item("UserName") = UserName
NoteDRV.Item("Note") = Note
NoteDRV.Item("NoteDate") = NoteDate
NoteDRV.Item("CompanyCode") = CompanyCode
NoteDRV.EndEdit()
NotesDA.UpdateCommand = NoteBuilder.GetUpdateCommand
NotesDA.Update(NotesDS, "Notes")
End If
End Using
End Using
End Using
End Using
Obviously, amend to make appropriate for your table and column names.
If you need to retrieve the ID for display, you can add a handler to the Update like:
Public Sub GenericOnRowUpdated(sender As Object, e As System.Data.SqlClient.SqlRowUpdatedEventArgs)
Dim newID As Integer = 0
Dim idCMD As SqlClient.SqlCommand = New SqlClient.SqlCommand("SELECT ##IDENTITY", SQLDBConnection)
If e.StatementType = StatementType.Insert Then
newID = CInt(idCMD.ExecuteScalar())
e.Row("ID") = newID
End If
End Sub
and use like:
AddHandler NotesDA.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf GenericOnRowUpdated)
NotesDA.Update(NotesDS, "Notes")
NewID = NoteDRV.Item("ID")
EDIT
First Example amended and explained below:
'Declare you connection to the SQL dB. Connection String looks like "Data Source=192.168.71.10\dBName; Initial Catalog=dBName; User ID=USER; Password='PASSWORD!';MultipleActiveResultSets=true" - You may well already have an open connection, and can use that instead. Not sure what your
StockBindingSource is...
Dim oConn As New SqlConnection("CONNECTION STRING")
'Open the connection
oConn.Open()
'Declare Your DataAdapter and initialise using your connection
Dim DA As New SqlDataAdapter With {.SelectCommand = New SqlCommand With {.Connection = oConn, .CommandText = "SELECT * FROM Stock WHERE ID=0"}}
'Declare you DataSet
Dim DS As New DataSet
'Fill Your DataSet with the Stock table from your DataAdapter
DA.Fill(DS, "Stock")
'Declare a DataView for easy use (really the same as using DS.Tables("Stock").DefaultView)
Dim DV As New DataView(DS.Tables("Stock"))
'Declare a CommandBuilder and initialise with your DataAdapter. This will now watch for changes made to your data and build the appropriate SQL UPDATE/INSERT/DELETE command. the "[" and "]" are in case any column names use reserved words
Dim Builder As New SqlCommandBuilder(DA) With {.QuotePrefix = "[", .QuoteSuffix = "]"}
'Decalre a DataRowView for data population, based on your DataView table structure
Dim R As DataRowView = DV.AddNew()
'Populate the fileds with your Form data
R("Supplier") = Supplier.Text
R("Producer_code") = ProducerCode.Text
R("Barcode") = Barcode.Text
R("Comp_name") = ComponentName.Text
R("Warehouse") = Warehouse.Text
R("Internal_Code") = InternalCode.Text
R("Description_IT") = ITDescr.Text
R("Description_EN") = ENDescr.Text
R("Quantity") = "0"
'Notify that the edit has finished
R.EndEdit()
'Get the SQL command from the CommandBuilder
DA.UpdateCommand = Builder.GetUpdateCommand()
'Execute the update (in this case it will be an INSERT)
DA.Update(DS, "Stock")
Related
Here's my .mdf database file that has 5 columns
I want to add each of those values from my Id column in a list
Private Sub Read_Click(sender As Object, e As EventArgs) Handles Read.Click
Try
If con.State = ConnectionState.Open Then
con.Close()
End If
con.Open()
cmd = con.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT Id FROM tablekongbago"
cmd.ExecuteNonQuery()
Dim dr As SqlClient.SqlDataReader
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
While dr.Read
element = dr.GetInt32(0).ToString()
End While
Catch ex As Exception
End Try
MessageBox.Show(element)
End Sub
The problem is that I can only retrieve the last row of my Id column and not all of the values from my Id column using
element = dr.GetInt32(0).ToString()
If I try to iterate and turn it into
dr.GetInt32(1).ToString()
it displays nothing.
I want to create a collection of Id's to a List(Of Integer) I know how to create a list and a for loop but I don't know how can I retrieve all of my Id's from my Id column, what kind of code should I use if "dr.GetInt32(0)" is only for the last row of the Id column?, is there a way I can loop starting from the very first top row up to the last row of my Id column? I want something like "list[0] - referring to the first row and list[2] - referring to the last row, so that I can add it my List(Of Integer).
I cringe whenever I see If con.State = ConnectionState.Open Then. Connections should be declared in the method where they are used. You should never have to question the ConnectionState.
You have executed your command twice. A Select in not a NonQuery. NoQuery is Insert, Update and Delete.
Your While loop keeps overwriting the element varaiable on each iteration so you only get the value in the last record.
Never write an empty Catch block. It will just swallow errors and you may get unexpected results with no clue why.
It is a good idea to separate you database code from you user interface code.
Create your connection and command with a Using...End Using block so you know they are properly disposed. Likewise with the reader. I like to do as little as possible with a reader because it requires and open connection and connections should be open for as short a time as possible.
Private ConStr As String = "Your connection string"
Private Sub Read_Click(sender As Object, e As EventArgs) Handles Read.Click
Dim dt As DataTable
Try
dt = GetIds()
Catch ex As Exception
MessageBox.Show(ex.Message)
Return
End Try
Dim ListOfIDs = (From row As DataRow In dt.AsEnumerable
Select CInt(row(0))).ToList
ListBox1.DataSource = ListOfIDs
End Sub
Private Function GetIds() As DataTable
Dim dt As New DataTable
Using con As New SqlConnection(ConStr),
cmd As New SqlCommand("SELECT Id FROM tablekongbago;", con)
con.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
You can simply create a List of Integer and add the ids to your collection during each call to dr.Read()
Dim ids = New List(Of Integer)()
While dr.Read()
ids.Add(dr.GetInt32(0))
End While
You code looks a bit messed up. This should work:
Note that a sql command object is VERY nice.
It has a reader built in - you don't need to define one
It has the command text - you don't need to define one
it has a connection object - again no need to create one (but you look to have one)
And using a dataTable is nice, since you can use for/each, or use the MyTable.Rows(row num) to get a row.
And a datatable is nice, since you don't need a loop to READ the data - use the built in datareader in sqlcommand object.
Using cmdSQL As New SqlCommand("Select Id FROM tblekingbago", con)
cmdSQL.Connection.Open()
Dim MyTable As New DataTable
MyTable.Load(cmdSQL.ExecuteReader)
' table is now loaded with all "ID"
' you can see/use/display/play/have fun with ID like this:
For Each OneRow As DataRow In MyTable.Rows
Debug.Print(OneRow("Id"))
Next
' display the 5th row (it is zero based)
Debug.Print(MyTable.Rows(4).Item("Id"))
End Using
Hi I'm trying to display a selected product on a listbox similar in this video:
https://www.youtube.com/watch?v=QbbZzaMZGhY
In the video, when he click an item from the listbox, its values appear(price and name) on the textbox. I reviewed the source code but he was not using a database. In my case, I need to use an access database to list all of my product and their id and price. Here's what I got so far from asking here:
Private Sub listboxitems_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles listboxitems.SelectedIndexChanged
Using lbconn As New OleDb.OleDbConnection("PROVIDER=Microsoft.ACE.Oledb.12.0; Data Source = C:\Users\USER PC\Desktop\orderDB1.accdb")
Using lbcmd As New OleDb.OleDbCommand("SELECT productid, product, price FROM productlog WHERE productid = ? AND product = ? AND price = ?", lbconn)
'Set your values here. The parameters must be added in the same order that they
'appear in the sql SELECT command
Dim prodidparam As New OleDbParameter("#productid", Me.txtproductid.Text)
Dim prodparam As New OleDbParameter("#product", Me.txtproduct.Text)
Dim priceparam As New OleDbParameter("#price", Me.txtprice.Text)
lbcmd.Parameters.Add(prodidparam)
lbcmd.Parameters.Add(prodparam)
lbcmd.Parameters.Add(priceparam)
'Open the connection
lbconn.Open()
txtproduct.Text = listboxitems.SelectedItem
Using lbreader As OleDbDataReader = lbcmd.ExecuteReader()
While lbreader.Read
txtproductid.Text = lbreader.GetInt32("productid").ToString()
txtproduct.Text = lbreader.GetString("product")
txtprice.Text = lbreader.GetString("price").ToString()
End While
End Using
End Using
End Using
End Sub
In the line:
txtproduct.Text = listboxitems.SelectedItem
I managed to show its name in the textbox, but its not coming from my database. I can't just type their price and name in the project but I need my data source to come from the database. So far nothing is showing up in the app. What am i missing? Thanks.
EDIT: The form load code where the listbox is filled with the database.
Private Sub shop_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Create a connection to the database
provider = "PROVIDER=Microsoft.ACE.Oledb.12.0; Data Source="
datafile = "C:\Users\USER PC\Desktop\orderDB1.accdb"
connString = provider & datafile
myConnection.ConnectionString = connString
'Open the connection with error handling
Try
If Not myConnection.State = ConnectionState.Open Then
End If
myConnection.Open()
Catch OleDbExceptionErr As OleDbException
MessageBox.Show(OleDbExceptionErr.Message)
Catch InvalidOperationErr As InvalidOperationException
MessageBox.Show(InvalidOperationErr.Message)
End Try
'Command Object. Select from productlog. 'productlog name of table'
Dim objcmd As New OleDbCommand("SELECT * FROM productlog", myConnection)
'data adapter and data table.
Dim da As New OleDbDataAdapter(objcmd)
Dim dt As New DataTable("productlog")
da.Fill(dt)
'Create connection and release resources
myConnection.Close()
myConnection.Dispose()
myConnection = Nothing
objcmd.Dispose()
objcmd = Nothing
da.Dispose()
da = Nothing
'fill from access to the listbox
For Each row As DataRow In dt.Rows
listboxitems.Items.Add(row.Item("product"))
Next
'Release resources
dt.Dispose()
dt = Nothing
End Sub
EDIT: CODE UPDATED
Private Sub listboxitems_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles listboxitems.SelectedIndexChanged
Using lbconn As New OleDb.OleDbConnection("PROVIDER=Microsoft.ACE.Oledb.12.0; Data Source = C:\Users\USER PC\Desktop\orderDB1.accdb")
Using lbcmd As New OleDb.OleDbCommand("SELECT productid, product, price FROM productlog WHERE product = ?", lbconn)
'Set your values here. The parameters must be added in the same order that they
'appear in the sql SELECT command
Dim prodparam As New OleDbParameter("#product", listboxitems.SelectedItem)
Dim prodidparam As New OleDbParameter("#productid", listboxitems.SelectedItem)
Dim prodpriceparam As New OleDbParameter("#price", listboxitems.SelectedItem)
lbcmd.Parameters.Add(prodparam)
lbcmd.Parameters.Add(prodidparam)
lbcmd.Parameters.Add(prodpriceparam)
'Open the connection
lbconn.Open()
txtproduct.Text = listboxitems.SelectedItem
Using lbreader As OleDbDataReader = lbcmd.ExecuteReader()
While lbreader.Read
txtproductid.Text = listboxitems.SelectedItem.ToString()' iknow im missing alot in this line of code i just dont know what that is'
txtproduct.Text = listboxitems.SelectedItem.ToString()
txtprice.Text = listboxitems.SelectedItem.ToString()
End While
End Using
End Using
End Using
End Sub
I changed the get statements cause im having an error that says cannot convert type integer to string. im sorry if im making this really hard stack overflow is like my first line of defense and my last resort at the same time.
Your query is wrong. You want to get back the productid, product and price from the productlog table WHERE the record searched is equal to the productid, product and price that you supply as parameters.
Did you see the problem?
If you already know these values why ask the database? I suppose that your task is to find the product and price given the product stored in the current list item. If so, there is no need to use the textboxes and your query should be
SELECT productid, product, price FROM productlog WHERE product = ?
And the parameter is the data extracted by the listbox item
Dim prodidparam As New OleDbParameter("#product", listboxitems.SelectedItem)
Now your code could reach the while loop and set the textboxes with the missing informations. Of course this works because you have distinct product names in your table (meaning, there are no two records with the same product name)
EDIT
Looking at your comments below it seems that you are really confused how to use the GetPos, GetString, GetInt32 and eventually GetDecimal.
Once you have called lbreader.Read() you have a record at your disposition to transfer into your textboxes. But there is little point to take in consideration. You should call the various GetXXXX appropriate for the datatype of the underlying column. This problem is often overlooked by VB.NET programmers used to the automatic type conversion applied by the VB.NET compiler. These conversions don't exist in the lower levels of NET and it is better to avoid these conversions at all to not fall in subtle problems.
However, to call a OleDbDatareader.GetXXXX you need the ordinal position of the field in the returned record. So you need to call first OleDbDataReader.GetPos and then use the value returned by GetPos to extract the info from the GetXXXXX call.
Using lbreader As OleDbDataReader = lbcmd.ExecuteReader()
While lbreader.Read
Dim pos = lbreader.GetPos("product")
txtProduct.Text = lbreader.GetString(pos)
pos = lbreader.GetPos("productid")
txtProductID.Text = lbreader.GetInt32(pos).ToString()
pos = lbreader.GetPos("Price")
txtPrice.Text = lbreader.GetDecimal(pos).ToString()
End While
End Using
The last line uses GetDecimal assuming the column Price to be a numeric decimal in your database (as it should being it a currency value), if not, then use the appropriate GetXXXXX. Note also that the two last GetXXXX returns an Int32 and a Decimal. To assign these values to a property of type string (like Text) you should use an explicit conversion to a string (ToString())
I am trying to navigate through records (next and prev) in a form that i have created in Microsoft Access 2013. The database is connected to SQL Server 2008. First i have loaded the database for the table using SQL:
Private Sub Form_Load()
Dim strSQL As String
Dim dbs As DAO.Database
Dim Rs As DAO.Recordset
Set dbs = CurrentDb()
strSQL = " SELECT [dbo_tblRank].* " & _
" FROM [dbo_tblRank] "
Set Rs = dbs.OpenRecordset(strSQL, dbOpenDynaset)
Me.rankNo.Value = Rs![rankNo]
Me.rankName.Value = Rs![rankName]
Me.rankDescription.Value = Rs![rankDescription]
Me.noOfRequiredDivings.Value = Rs![noOfRequiredDivings]
End Sub
Now i have created a 'next' button, which i would like to update the following fields to the next values. I have written the code (which doesn't do anything):
Private Sub btnNext_Click()
Me.Recordset.MoveNext
End Sub
What Am i doing wrong?
The issue is that the form is unbound. As a result of this, you've had to write more code in form_open than would have been required were the form/controls bound; Similarly then, in btnNext_Click, you will again have to write more code.
Re-create the recordset, find the current record in the recordset, then move to the next record, and then re-populate your unbound controls from the new record in this new recordset.
Another way would be for you to make you recordset public so that you don't have to reconnect each time.
You will still have to write code to find the current record so that you can move pass it in your btnNext_Click event.
The easy way would be to bound your Form...
I have 37 columns in DataGridView (Access database), except the first column, every cell in 50x36 table is changeable with mouse click (click on cell gives value of "X", another click ""). Is it possible to completely update Access database from DataGridView, basically overwrite Access database table with DataGridView data table?
I don't know how to do that differently, since there are changes all over the place in one session, not only in one row of the database, so I really would know how to implement INSERT into all that.
DatagridView is populated with this code.
Dim ConnString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=w:\PD_Z.mdb"
Dim SQLString As String = "SELECT * FROM ZARADE"
Dim OleDBConn1 As System.Data.OleDb.OleDbConnection = New System.Data.OleDb.OleDbConnection(ConnString)
Dim DataSet1 As New DataSet()
Dim OleDbDataAdapter1 As System.Data.OleDb.OleDbDataAdapter = New System.Data.OleDb.OleDbDataAdapter(SQLString, OleDBConn1)
OleDBConn1.Open()
OleDbDataAdapter1.Fill(DataSet1, "ZARADE")
DataGridView1.DataSource = DataSet1.Tables("ZARADE")
DataGridView1.Columns.Remove(DataGridView1.Columns(0).Name)
OleDBConn1.Close()
You could use the OleDbCommandBuilder class to build your queries automatically. But it generates only single table commands.
Since you already have the OleDbDataAdapter instance, use the same to update the database.
Sample code:
Dim cb As New OleDbCommandBuilder(OleDbDataAdapter1);
cb.QuotePrefix = "[";
cb.QuoteSuffix = "]";
OleDbDataAdapter1.Update(DataSet1.Tables("ZARADE"))
I'm sure my question has been answered many times on the internet, but I couldn't find exactly what I was looking for.
I'm working on VB.NET and my database is a SQL Server Compact .SDF file. The following is my method of opening the database.
Private Shared Sub OpenDatabase(ByVal tablename As String)
If _DBLoaded Then Return
'// open database connection
conn = New SqlCeConnection("Data Source = giadatabase.sdf")
conn.Open()
'// create command for making extracting data
cmd = conn.CreateCommand
cmd.CommandText = "SELECT * FROM [" & tablename & "]"
'// setup database adapter
da = New SqlCeDataAdapter(cmd)
'// create command for inserting/updating database
cb = New SqlCeCommandBuilder(da)
'// load dataset
ds = New DataSet()
da.Fill(ds)
'// get the relevant table
dt = ds.Tables(0)
_DBLoaded = True
End Sub
I run this sub when my application starts. I believe that database needs to be opened just once. Constantly reopening of database will cause performance problems to my application (correct me if I'm wrong).
For loading data in my list object I use the following:
Public Shared Function GetList() As List(Of DatabaseListObject)
OpenDatabase("TestTable")
'// Make a list of items in database
Dim ret As New List(Of DatabaseListObject)
For Each dRow As DataRow In dt.Rows
ret.Add(New DatabaseListObject(dRow("ID"), dRow("LongName"), dRow("ShortName")))
Next
Return ret
End Function
So my GetList function ensures database is already open, and database is always opened once a lifetime of my application. My list object is filled with data from the above function.
This is how I make changes to my database:
Public Shared Function AddItem(LongName As String, ShortName As String) As DatabaseListObject
'// Make changes
Dim row = dt.NewRow()
row("LongName") = TimeOfDay.ToString
row("ShortName") = ShortName
dt.Rows.Add(row)
da.Update(ds, dt.TableName)
Dim newcmd = conn.CreateCommand
newcmd.CommandText = "SELECT ##IDENTITY;"
Dim newID As Integer = newcmd.ExecuteScalar()
Dim item As New DatabaseListObject(newID, LongName, ShortName)
Return item
End Function
Now I assume database is correctly updated from the above code. The ID column in my table is the autonumber. Problem occurs when I call the GetList function after adding a row. System throws error that the newly added row's ID column is NULL. Whereas it should be automatically added number. When I restart the application, i.e. the database is opened from scratch, then the GetList shows the autonumber properly.
Obviously the table's ID column is not getting filled-in with the autonumber when I'm adding a new row. So I need suggestions here. Should I always open the database from scratch whenever I call the GetList (which will be called frequently in my app). If not the entire database then which codes should be called at least to properly refresh the table without causing much performance problems to the application.
SELECT ##IDENTITY will only Work on the same open Connection object, and the DataAdapter opens and Closes its own connection, you must use plain ADO.NET (cmd.ExecuteNonQuery) or implemet extra code as described here: http://blogs.msdn.com/b/bethmassi/archive/2009/09/15/inserting-master-detail-data-into-a-sql-server-compact-edition-database.aspx