I'm just trying to insert some data, I've doubled check my table definition and my variables data type
This is my table definition in mdf database file
product_id - int
product_name - varchar(50)
qty_sold - int
date - date
and this is my list
Dim cart As New List(Of Integer)
Dim product_qty As New List(Of Integer)
I'm trying to insert using this code
For i As Integer = 0 To cart.Count - 1
cmd.CommandText = "insert into sales values('" + cart(i) + "', '" + getName(cart(i)) + "', '" + product_qty(i) + "', '" + datefield.Text + "')"
cmd.ExecuteNonQuery()
i = i + 1
Next
getName returns a String so it fits with the product_name column while datefield.Text returns a date format
and I'm getting this error, some sort of data type error with Double thing I think.
System.InvalidCastException: 'Conversion from string "insert into sales values('" to type 'Double' is not valid.'
Change the name of the date column to SaleDate. You will avoid extra work trying to except the name date as a reserved word or type in .net. Always list the fields you are inserting. Otherwise your inserts are positional. DBAs have been known to add fields and you may have missed the memo.
I created 2 classes to hold your data. Fill you class' instances with your data from the user interface or wherever. Add the instances to the lists.
Then pass the lists to the InsertSales method.
The the Connection, Command, and ParametersCollection are created only once outside the loops. The connection is opened outside the loop. Only the values of the values of the parameters change inside the loops. The command is executed on each iteration of the inner loop.
Public Class Cart
Public CartDate As Date
Public CartContents As New List(Of ProductSale)
End Class
Public Class ProductSale
Public ProcuctID As Integer
Public ProductName As String
Public QuantitySold As Integer
End Class
Private Carts As New List(Of Cart)
Private Products As New List(Of ProductSale)
Private Sub InsertSales(CartList As List(Of Cart), ProductList As List(Of ProductSale))
Dim sql = "insert into sales (product_id, product_name, qty_sold, saledate) values (#ProductId, #ProductName, #QuantitySold, #DateSold)"
Using con As New SqlConnection(ConStr),
cmd As New SqlCommand(sql, con)
cmd.Parameters.Add("#ProcuctID", SqlDbType.Int)
cmd.Parameters.Add("#ProductName", SqlDbType.VarChar, 50)
cmd.Parameters.Add("#QuanitySold", SqlDbType.Int)
cmd.Parameters.Add("#DateSold", SqlDbType.Date)
con.Open()
For Each c As Cart In CartList
cmd.Parameters("#DateSold").Value = c.CartDate
For Each p As ProductSale In c.CartContents
cmd.Parameters("#ProductID").Value = p.ProcuctID
cmd.Parameters("#ProductName").Value = p.ProductName
cmd.Parameters("#QuantitySold").Value = p.QuantitySold
Next
cmd.ExecuteNonQuery()
Next
End Using
End Sub
BTW, it is redundant to have columns for both product id and product name. I presume there is a Products table with product Id as the primary key and a column for product name. You are storing the same data twice. Suppose they change the product name. You would have to do a huge update.
Related
Im making a POS style system and this is my code for storing the data for the active order and also inputting the data into the database. This should all work however I get an error on the cmd.ExecuteNonQuery() in the "Push" IF statement.
It gives me an SQLite error 20: Datatype mismatch.
And idea why?
TIA
Imports Microsoft.Data.Sqlite
Public Class CurrentOrder
Public Shared OrderID As Integer
Public Shared Items As New ArrayList
Public Shared ItemsString As String
Public Shared CustName As String
Public Shared Table As Integer
Public Shared Cost As Double 'How much the restaurant will have to pay to make the meal
Public Shared Price As Double 'How much the customer will pay for this order
Public Shared Sub Database(ByVal Mode As String)
Dim Connection As New SqliteConnection("Data Source = Database.db")
Dim SQLcommand As String
Dim CMD As New SqliteCommand
'ItemsString = ""
If Items.Count = 0 Then
MessageBox.Show("Please add items to order", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If
If Mode = "Push" Then
For i = 0 To Items.Count - 1
ItemsString = ItemsString + Items(i) 'Concatatanation to take a list to a string
Next
Order.Label3.Text = ItemsString
SQLcommand = "INSERT INTO Orders VALUES ('#OrderID', '#ItemsString', '#CustName', '#Table', '#Cost', '#Price')" 'SQL Push Statement
Try
CMD.Connection = Connection
Connection.Open()
CMD.CommandText = SQLcommand
CMD.ExecuteNonQuery() 'Error 20: Datatype mismatch
Connection.Close()
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
ElseIf Mode = "Pull" Then
SQLcommand = ("SELECT * FROM Orders WHERE OrderID = " & OrderID) 'SQL Pull Statement
Try
CMD.Connection = Connection
Connection.Open()
CMD.CommandText = SQLcommand
Dim reader As SqliteDataReader = CMD.ExecuteReader()
While reader.Read()
Order.Label3.Text = reader("ItemID") & ", " & reader("Name") & ", " & reader("Price")
End While
reader.Close()
Connection.Close()
Catch e As Exception
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End If
End Sub
End Class
When dealing with money it is better to use Decimal rather than Double.
I don't know why this class has all these Shared items. It would probably be better to just create an instance in the calling code.
ArrayList should not be used in new code. See if List(Of T) will fill the bill.
Fields are not normally Public in Classes. You want a Property to be Public.
Classes like this have no user interface. You don't want to show message boxes from your class. Show the message boxes from you User Interface code in the Form Class.
Do not store several items in a single field in the database. You should have an Orders table with a primary key OrderID and an OrderDetails table for the items.
Your for loop just lumps all the items together. You will not be able to pull them apart again without any delimiter. Also, the concatenation operator in vb.net is &.
For you insert statement it is usually best to list the field names and then the values. I don't know why you're enclosed the parameter names in single quotes.
You can pass the CommandText and the Connection directly to the constructor of the Command.
You have referenced several parameters in your insert but you never added them to the parameters collection or set a value for them.
Apparently, you are providing a unique value for OrderID and this is not an auto number field.
Use a Sub New to put your order object in a stable state ready to have its data added to the database.
Public Class CurrentOrder
Public Property OrderID As Integer
Public Property Items As New List(Of String)
Public Property CustName As String
Public Property Table As Integer
Public Property Cost As Decimal 'How much the restaurant will have to pay to make the meal
Public Property Price As Decimal 'How much the customer will pay for this order
Public Sub New(ID As Integer, Itms As List(Of String), Name As String, TBL As Integer, Cst As Decimal, Prc As Decimal)
OrderID = ID
Items = Itms
CustName = Name
Table = TBL
Cost = Cst
Price = Prc
End Sub
End Class
The CurrentOrder class is completely separate from the DataAccess class.
Public Class DataAccess
Private ConStr As String = "Data Source = Database.db"
Public Sub SaveOrderAndDetails(O As CurrentOrder)
Dim OrderInsert = "INSERT INTO Orders (OrderID, CustName, Table, Cost, Price) VALUES (#OrderID, #CustName, #Table, #Cost, #Price)"
Using Connection As New SQLiteConnection(ConStr)
Using CMD As New SQLiteCommand(OrderInsert, Connection)
CMD.Parameters.Add("#OrderID", DbType.Int32).Value = O.OrderID
CMD.Parameters.Add("#CustName", DbType.String).Value = O.CustName
CMD.Parameters.Add("#Table", DbType.Int32).Value = O.Table
CMD.Parameters.Add("#Cost", DbType.Decimal).Value = O.Cost
CMD.Parameters.Add("#Price", DbType.Decimal).Value = O.Price
Connection.Open()
CMD.ExecuteNonQuery()
End Using
Dim DetailsInsert = "Insert Into OrderDetails (OrderID, Item) Values (#OrderId, #Item)"
Using cmd As New SQLiteCommand(DetailsInsert, Connection)
cmd.Parameters.Add("#OrderId", DbType.Int32).Value = O.OrderID
cmd.Parameters.Add("#Item", DbType.String)
For Each s In O.Items
cmd.Parameters("#Item").Value = s
cmd.ExecuteNonQuery()
Next
End Using
End Using
End Sub
Public Function GetOrderByID(id As Integer) As DataTable
Dim dt As New DataTable
Dim SqlCommand = "SELECT * FROM Orders WHERE OrderID = #ID"
Using cn As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(SqlCommand, cn)
cmd.Parameters.Add("#ID", DbType.Int32).Value = id
cn.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Public Function GetOrderDetailByID(id As Integer) As DataTable
Dim dt As New DataTable
Dim sql = "Select Item From OrderDetails Where OrderID = #ID"
Using cn As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(sql, cn)
cmd.Parameters.Add("#ID", DbType.Int32).Value = id
cn.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
End Class
Finally, the usage of the classes in the user interface, in this case a windows form.
Private Sub Button1_Click() Handles Button1.Click
Dim lst As New List(Of String)
lst.Add("Bacon")
lst.Add("Eggs")
Dim newOrder As New CurrentOrder(7, lst, "John", 4, 12.03D, 22D)
Dim DA As New DataAccess
DA.SaveOrderAndDetails(newOrder)
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim DA As New DataAccess
Dim dt = DA.GetOrderByID(7)
'Fill various text boxes with the DataTable fields
Dim dt2 = DA.GetOrderDetailByID(7)
DataGridView1.DataSource = dt2
End Sub
In the table, you have a different data type and you are sending a different datatype. For Example, In the table, you use Int and you pass decimal.
I'm trying to update product_qty inside my mdf file database based on values given in my two list of Integers, I basically just want to loop inside of my list to gather IDs and a collection of quantities inside product_qty() list. I just want to subtract quantites here
For i As Integer = 0 To cart.Count - 1
cmd.CommandType = CommandType.Text
cmd.CommandText = "UPDATE product SET product_qty= product_qty - #qty WHERE product_id= #id"
cmd.Parameters.AddWithValue("#qty", product_qty(i))
cmd.Parameters.AddWithValue("#id", cart(i))
i = i + 1
cmd.ExecuteNonQuery()
Next
This is my list data type filled with IDs and quantities
Dim cart As New List(Of Integer)
Dim product_qty As New List(Of Integer)
Exact syntax is probably a little off as I'm doing this from memory, but concept is what I'm going for so should be enough to get you going in the right direction with a little research.
cmd.CommandType = CommandType.Text
cmd.CommandText = "UPDATE product SET product_qty= product_qty - #qty WHERE product_id= #id"
cmd.Parameters.Add("#qty", SqlDbType.Int32)
cmd.Parameters.Add(("#id", SqlDbType.Int32)
For i As Integer = 0 To cart.Count - 1
cmd.Parameters("#id").value = cart(1)
cmd.Parameters("#qty").value = product_qty(i)
cmd.ExecuteNonQuery()
Next
Key thing is, you setup the sql command outside the loop first, then withing the loop all you need to do is update the value of the pre-existing parameters.
Normally I would not have the linq code to get ShorterList in the database code but it is unpleasant (maybe impossible) to use anonymous types outside the method where they are created.
The Using...End Using blocks ensure that the connection is closed and disposed and the command is disposed. Using should be used with any type that exposes a .Dispose method.
The rest is the same as my answer to Why I'm getting System.InvalidCastException when inserting in mdf database file
Public Class Cart
Public CartDate As Date
Public CartContents As New List(Of ProductSale)
End Class
Public Class ProductSale
Public ProcuctID As Integer
Public ProductName As String
Public QuantitySold As Integer
End Class
Private ConStr As String = "Your connection string"
Private Carts As New List(Of Cart)
Private Products As New List(Of ProductSale)
Private Sub UpdateInventory(Products As List(Of ProductSale))
Dim ShorterList = (From p In Products
Group By ID = p.ProcuctID
Into g = Group, Sum(p.QuantitySold)
Select ID, Sum).ToList
'To optimize the Update use Group By and sum on the resultant list so each product is only updated once.
Dim sql = "UPDATE product SET product_qty= product_qty - #Quantity WHERE product_id= #Id"
Using con As New SqlConnection(ConStr),
cmd As New SqlCommand(sql, con)
cmd.Parameters.Add("#Quantity", SqlDbType.Int)
cmd.Parameters.Add("#Id", SqlDbType.Int)
con.Open()
For Each a In ShorterList
cmd.Parameters("#Quantity").Value = a.Sum
cmd.Parameters("#Id").Value = a.ID
cmd.ExecuteNonQuery()
Next
End Using
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst As New List(Of ProductSale)
'Combine all the carts contents to a single list
For Each c As Cart In Carts
lst.AddRange(c.CartContents)
Next
UpdateInventory(lst)
End Sub
I'm trying to get the database value of an item that i put on a listbox to display to the textbox. (vb.net)
My database table name is 'productlog', in this table has 3 columns, productid, productname, and price. I got the productname to display on a listbox that I made, now I am attempting to display the 3 columns on 3 textboxes. However, I get the "data type mismatch in criteria expression" error on my ExecuteReader line. Here's my code:
Public Class shop
Dim provider As String
Dim datafile As String
Dim connString As String
Dim myConnection As OleDbConnection = New OleDbConnection
Private Sub listboxitems_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles listboxitems.SelectedIndexChanged
Dim lbconn As New OleDb.OleDbConnection("PROVIDER=Microsoft.ACE.Oledb.12.0; Data Source = C:\Users\USER PC\Desktop\orderDB1.accdb")
Dim lbcmd As New OleDb.OleDbCommand("SELECT productid, product, price FROM productlog WHERE productid =' & listboxitems.Text & ' AND product ='" & listboxitems.Text & "' AND price =' & listboxitems.Text & '", lbconn)
Dim lbreader As OleDbDataReader
lbconn.Open()
lbreader = lbcmd.ExecuteReader() 'error appearing right here'
While lbreader.Read
txtproductid.Text = lbreader.GetInt32("productid")
txtproduct.Text = lbreader.GetString("product")
txtprice.Text = lbreader.GetInt32("price")
End While
lbconn.Close()
End Sub
Based on the other questions that I looked up, it might be because that 'productid' and 'price' are both integers and what I'm doing is for a String. I tried to remove the double quotes ('"& txtproductid.Text"') and turn them into 'txtproductid.Text', based from another question I looked up. The another answer that I saw was to convert the string into an integer - 'lbcmd.Parameters.AddwithValue("#productid", ConvertInt32("txtproductid.Text"))' not sure if that's correct but I ended up getting the same error. How do I work around this error? Thanks.
UPDATED CODE:
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()
Using lbreader As OleDbDataReader = lbcmd.ExecuteReader()
While lbreader.Read
txtproductid.Text = lbreader.GetInt32("productid").ToString()
txtproduct.Text = lbreader.GetString("product")
txtprice.Text = lbreader.GetInt32("price").ToString()
End While
End Using
End Using
End Using
End Sub
You should not use string concatenation to create your SQL query as you are doing here. That opens you up to a sql injection hack. Instead you should use a parameterized query.
Try something like this (not tested):
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
lbcmd.Parameters.Add("productid", OleDb.OleDbType.Integer).Value = 1234
lbcmd.Parameters.Add("product", OleDb.OleDbType.VarChar).Value = "value of product"
lbcmd.Parameters.Add("price", OleDb.OleDbType.Integer).Value = 999
'Open the connection
lbconn.Open()
Using lbreader As OleDbDataReader = lbcmd.ExecuteReader()
While lbreader.Read
txtproductid.Text = lbreader.GetInt32("productid").ToString()
txtproduct.Text = lbreader.GetString("product")
txtprice.Text = lbreader.GetInt32("price").ToString()
End While
End Using
End Using
End Using
Since your code is using OleDbConnection you can't use named parameters. Note the question marks in the SELECT statement which server as placeholders for the values.
Note that when using OleDb, you have to add the parameters in the same order as they appear in your sql query.
The Using ... End Using statements ensure that the connection, command and datareader are disposed properly.
I created 3 Tables in ms access in which the Table Person is the only one that contains a Primary key TABLE PERSON(ID,FNAME,MNAME,LNAME) , and i connect it to 2 TABLES AMOUNT(ID,amount,Term ), TABLE TIME(ID,start,due).
The time table and id table has no PK and ID formats are Numbers.
When I try to add Data in my Database using Vb.Net it shows this error You cannot add or change a record because a related record is required in table 'P'.
Here is the whole code:
Public Function insert_person(ByVal fname As String, ByVal mname As String, ByVal lname As String)
Dim connect As OleDbConnection = con()
Dim cmd As OleDbCommand = connect.CreateCommand()
cmd.CommandText = "insert into P(fname,mname,lname)values(fname,mname,lname)"
cmd.Parameters.Add("#fname", OleDbType.VarChar).Value = fname
cmd.Parameters.Add("#mname", OleDbType.VarChar).Value = mname
cmd.Parameters.Add("#lname", OleDbType.VarChar).Value = lname
cmd.ExecuteNonQuery()
connect.Close()
Return 0
End Function
Public Function insert_amount(ByVal empid As Integer, ByVal amount As Double, ByVal term As Integer)
Dim connect As OleDbConnection = con()
Dim cmd As OleDbCommand = connect.CreateCommand()
cmd.CommandText = "insert into A(empid,amount,term) values(#empid,#amount,#term)"
cmd.Parameters.Add("#empid", OleDbType.Integer).Value = empid
cmd.Parameters.Add("#amount", OleDbType.Double).Value = amount
cmd.Parameters.Add("#term", OleDbType.Integer).Value = term
cmd.ExecuteNonQuery()
connect.Close()
Return 0
End Function
When i check my DB to see if The records had been saved the only record saved is TABLE P TABLE amount TABLE time do not add anything
You have a syntax error in insert_amount:
cmd.Parameters.Add(New OleDbParameter(CType("[empid]"
time is a reserved word in Access, you should name this table differently.
Every table should have a primary key. You'll get all sorts of problems without.
The error message you get means that you have a relationship with Referential Integrity between P and the other tables. You need to pass and insert an empid that exists in P.
I didn't write the function for the AutoCompleteExtender so I am not quite sure how to change it without screwing it up, so I figured I would ask here. Recently, it was requested that the AutoComplete show a product name & the date of launch of that specific product. I do not know how to add the date to the AutoComplete.
The reason this is needed is because the webinars we give out are shown again in the future, so there are multiple webinars with the same name in the database. It is a little difficult to choose one webinar when searching when there are 3 with the exact same name, so if it shows the name and the date, I would imagine it would be easier to choose the right one!
The way this is written right now is incorrect. I get a squiggly line underneath the word launchdate in the line Dim item As String = AjaxControlToolkit...... and the error is: Too many arguments to 'Public Shared Function CreateAutoCompleteItem(text As String, value As String) As String'
Any help is greatly appreciated! Like I said, I didn't write this, so I don't even know if this is best practice. I understand if you want to criticize the code, and I will change it if it needs it, but I would really like to know how to add the extra field too. Thanks!
Public Function GetProducts(ByVal prefixText As String, ByVal count As Integer) As String()
Dim ProductSql As String = "Select DISTINCT ProductID, ProductName, LaunchDate
FROM Product
WHERE ProductName LIKE '%' + #prefixText + '%'
AND LaunchDate IS NOT NULL
ORDER BY ProductName ASC"
Using sqlConn As New SqlConnection
(System.Configuration.ConfigurationManager.ConnectionStrings("LocalSqlServer").ConnectionString)
sqlConn.Open()
Dim myCommand As New SqlCommand(ProductSql, sqlConn)
myCommand.Parameters.Add("#prefixText", SqlDbType.VarChar, 50).Value = prefixText
Dim myReader As SqlDataReader = myCommand.ExecuteReader()
Dim myTable As New DataTable
myTable.TableName = "ProductSearch"
myTable.Load(myReader)
sqlConn.Close()
Dim items As String() = New String(myTable.Rows.Count - 1) {}
Dim i As Integer = 0
For Each dr As DataRow In myTable.Rows
Dim id As String = dr("ProductID").ToString()
Dim name As String = dr("ProductName").ToString()
Dim launchdate As String = dr("LaunchDate").ToString()
Dim item As String =
AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(name, id, launchdate)
items.SetValue(item, i)
i += 1
Next
Return items
End Using
End Function
Try this..
AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(name & " " & launchdate, id)