I'm trying to copy rows from one DataTable to another, but only copy rows where the data is yet to be saved to the database table.
The SQL side of this is working fine, it's returning the correct number of columns, however, when I add the rows that were found to my second DataTable and set it as the DataSource for my grid, there is no data displayed, although there is a row that has been added, since the row selector is visible.
What am I doing wrong, and why isn't the data being copied with it?
lftable = New DataTable
Try
For Each dc As DataColumn In lineTable.Columns
lftable.Columns.Add()
Next
Dim ds As New DataSet
For Each row As DataRow In lineTable.Rows
Dim da As New OleDbDataAdapter("SELECT * FROM [Order_Freight] WHERE [Order_Number] = ? AND [Product_Code] <> ?", con)
da.SelectCommand.Parameters.Add("#num", OleDbType.Integer).Value = orderNum
da.SelectCommand.Parameters.Add("#prod", OleDbType.VarChar).Value = row.Item("Product_Code")
da.Fill(ds)
For Each dr As DataRow In ds.Tables(0).Rows
Dim nRow = lftable.Rows.Add()
nRow.ItemArray = dr.ItemArray()
Next
Next
ugProducts.DataSource = lfTable
Screenshot of the grid after assigning it the DataSource
Fill the columns correctly:
For Each dc As DataColumn In lineTable.Columns
lftable.Columns.Add(new DataColumn(dc.ColumnName, dc.DataType));
Next
You can use the overload of the Row.Add function which allows you provide the ItemArray directly:
For Each dr As DataRow In ds.Tables(0).Rows
lftable.Rows.Add(dr.ItemArray)
'nRow.ItemArray = dr.ItemArray() <-- remove
Next
Instead of this code :
' For Each dc As DataColumn In lineTable.Columns
' lftable.Columns.Add() >
' lftable.Columns.Add(dc)
' Next
Use DataTable.Clone() to copy only the columns in a lineTable to lftable
lftable = lineTable.Clone();
And then
For Each dr As DataRow In ds.Tables(0).Rows
lftable.Rows.Add( dr.ItemArray)
Next
Related
I have designed a SQL Server database app in which I fetch data from database and then insert in text boxes. I use a function to fetch data in data table from database and then I populate textboxes. I have to use this coding again and again:
If Dt.Rows.Count > 0 Then
TxtCust_Id.Text = Dt.Rows(0).Item(0)
TxtCust_City.Text = Dt.Rows(0).Item(1)
TxtCust_Area.Text = Dt.Rows(0).Item(2)
Else
TxtCust_Id.Text = String.Empty
TxtCust_City.Text = String.Empty
TxtCust_Area.Text = String.Empty
End if
Text boxes names changes according to query tables. My question is. Is it possible to make a function or procedure to populate data in text boxes from datatable using loops or any other method? Thanks in advance.
Shared Function ExecuteSelectDt(ByVal SelectCommand As String) As DataTable
Cmd = New SqlClient.SqlCommand
Sda = New SqlDataAdapter
' Dt = New DataTable
Try
DBConnection() ' Database connection details
Sda = New SqlDataAdapter(SelectCommand, Con)
Dim dt2 As New DataTable
Sda.Fill(dt2)
CloseConnection()
Return dt2
Catch ex As Exception
CloseConnection()
MsgBox(ex.Message)
Return dt
End Try
End Function
Private Sub TxtCust_Name_Leave(sender As Object, e As EventArgs) Handles TxtCust_Name.Leave
SQuery = "select Cust_Id, Cust_City, Cust_Area from TBLCustommers where Cust_Name= '" & TxtCust_Name.Text & "'"
Dt = Nothing
Dt = BM_Class_Liberary.SQLSereverDB.ExecuteSelectDt(SQuery)
If Dt.Rows.Count > 0 Then
TxtCust_Id.Text = Dt.Rows(0).Item(0)
TxtCust_City.Text = Dt.Rows(0).Item(1)
TxtCust_Area.Text = Dt.Rows(0).Item(2)
Else
TxtCust_Id.Text = String.Empty
TxtCust_City.Text = String.Empty
TxtCust_Area.Text = String.Empty
End if
End Sub
'create and populate list
dim txtBoxes as new List(of TextBox)();
for each ctrl as Control in Form.Controls
if ctrl.GetType() Is GetType(TextBox) then txtBoxes.Add(ctrl)
next
' then do this when you get DataTable
dim theRow as DataRow = dt.Rows(0); ' whatever logic you have to getting needed row
for each col as DataColumn in dt.Columns
' use system.linq
txtBoxes.First(function(tb) tb.Name = col.ColumnName).Text = theRow(col.ColumnName).ToString()
next
Note, when theRow(col.ColumnName) is DBNull.Value, ToString will return string.Empty, which is fine because .Text can't have Nothing
Also, I used First because I did it with the premise that each column has text box.
Or, using the dictionary. Even better, I think
'create and populate dictionary
dim txtBoxes as new Dictionary(of string, TextBox)();
for each ctrl as Control in Form.Controls
if ctrl.GetType() Is GetType(TextBox) then txtBoxes.Add(ctrl.Name, ctrl)
next
' then do this when you get DataTable
dim theRow as DataRow = dt.Rows(0); ' whatever logic you have to getting needed row
for each col as DataColumn in dt.Columns
txtBoxes(col.ColumnName).Text = theRow(col.ColumnName).ToString()
next
(I should say that im fairly new to vb.net)
I'm having a problem overwriting the entries in my database. I think the problem is that SqlDataAdapter.Update isn't overwriting the database properly with the new datatable info that i've created.
As I understand it, it should totally replace the the info in the database with the datatable when i tell it to update... no?
Here's the problem in a nutshell:
Basically, I have a database (.mdf file) with a table in it called 'test'. I've used SqlDataAdapter to make a dataset using 'test'. I have another datatable that I've made from parsing in a csv - it's called 'ToLoad'. I now want to clear the 'test' datatable, copy in all entries from the csv datatable, then save this to the database.
I've debugged all this and it all seems to work ok, except when I use SqlDataAdapter.Update I get an error telling me I cant duplicate the primary key. This is because the old entries aren't being cleared from the database entirely, before the new ones are being entered from the datatable.
I've checked that the test datatable is being actually cleared early on in the code... and it is.
I've checked that the new csv entries are being copied to the 'test' datatable... and they are.
Any help you can give on this would be really appreciated
Thanks
Craig
'MAKE A NEW SQL CONNECTION
Dim DBConnection As New SqlConnection
'SET THE CONNECTION STRING.
DBConnection.ConnectionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Project\Members.mdf;Integrated Security=True"
'OPEN THE CONNECTION TO THE DATABASE
DBConnection.Open()
'OPEN AN ADAPTER AND SELECT EVERYTHING FROM THE 'TEST' TABLE
Dim mySqlDataAdapter As New SqlDataAdapter("SELECT * FROM Test", DBConnection)
Dim mySqlCommandBuilder As New SqlCommandBuilder(mySqlDataAdapter)
Dim DBDataset As DataSet = New DataSet
'FILL THE DATASET WITH THE TEST TABLE
mySqlDataAdapter.Fill(DBDataset, "Test")
'CLEAR ALL ENTRIES IN THE DATATABLE (SO I CAN FILL IT FROM SCRATCH)
DBDataset.Tables("test").Clear()
''SET UP A LOOP TO ADD EACH RECORD FROM THE CSV DATATABLE TO THE DATABASE DATATABLE
Dim CSV_row_number As Int16
CSV_row_number = ds.Tables("toload").Rows.Count
Dim i As Int16
i = 0
Do Until i = CSV_row_number - 1
'MAKES TWO NEW DATAROW OBJECTS
Dim DB_row As DataRow
Dim CSV_row As DataRow
'SET THE CSV_ROW OBJECT EQUAL TO ROW(i) OF THE CSV DATATABLE
CSV_row = ds.Tables("toload").Rows(i)
DB_row = DBDataset.Tables("test").NewRow()
'THIS SETS ALL OF THE COLUMNS IN THIS NEW ROW AS EQUAL TO ROW1 IN THE CSV DATATABLE
DB_row("Name") = CSV_row("Name")
DB_row("Quality") = CSV_row("Address")
DBDataset.Tables("test").Rows.Add(DB_row)
i = i + 1
Loop
mySqlDataAdapter.Update(DBDataset.Tables("Test"))
I managed to fix this myself after a fair bit of googling and some trial and error. Posting my code in case it's useful for anyone else
Craig
'MAKE A NEW SQL CONNECTION
Dim DBConnection As New SqlConnection
'SET THE CONNECTION STRING. YOU GET THIS BY GOING TO SERVER EXPLORER, THEN CLICKING ON THE DATABASE
'THE CONNECTION STRING IS IN PROPERTIES
DBConnection.ConnectionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\ME\Project\Members.mdf;Integrated Security=True"
'OPEN THE CONNECTION TO THE DATABASE
DBConnection.Open()
'THIS OPENS AN ADAPTER TO THE DATABASE, AND SELECTS EVERYTHING FROM THE 'TEST' TABLE IN THAT DATABASE
Dim mySqlDataAdapter As New SqlDataAdapter("SELECT * FROM MemberList", DBConnection)
'THIS LETS US USE SQL ON THE DATATABLE (IT GETS PASSED THE ABOVE SQL STATEMENT)
Dim mySqlCommandBuilder As New SqlCommandBuilder(mySqlDataAdapter)
'THIS MAKES ANOTHER NEW DATASET
Dim DBDataset As DataSet = New DataSet
''THIS FILLS THAT DATASET WITH THE TEST TABLE (WHICH THE DATA ADAPTOR GRABBED ABOVE)
mySqlDataAdapter.FillSchema(DBDataset, SchemaType.Source, "MemberList")
mySqlDataAdapter.Fill(DBDataset, "MemberList")
'THIS MAKES A NEW DATATABLE
'I THEN MAKE ALL CHANGES NEEDED
Dim EDITmembers As DataTable
EDITmembers = DBDataset.Tables("MemberList")
''FIRST, IM GOING TO CLEAR ALL ENTRIES IN THE DATATABLE (SO I CAN FILL IT FROM SCRATCH)
'COUNT THE NUMBER OF ENTRIES TO CLEAR
Dim RowsInDB As Integer
RowsInDB = EDITmembers.Rows.Count()
'SET UP A LOOP TO CLEAR THEM
Dim Data_row As DataRow
Dim k As Integer = 0
Do Until k = RowsInDB
Data_row = EDITmembers.Rows(k)
Data_row.Delete()
k = k + 1
Loop
'ONCE ALL THE ROWS ARE CLEARED, SAVE THE CHANGES BY UPDATING THE ACTUAL DATABASE
mySqlDataAdapter.Update(DBDataset, "MemberList")
''THEN I SET UP A LOOP TO ADD EACH RECORD FROM THE CSV DATATABLE TO THE DATABASE DATATABLE
''I FIRST NEED TO KNOW HOW MANY ITERATIONS OF THE LOOP TO DO
Dim CSV_row_number As Int16
'COUNT THE NUMBER OF ROWS AND SET THE ABOVE INT EQUAL TO THIS
CSV_row_number = ToLoad.Rows.Count
Dim j As Int16
j = 0
Do Until j = CSV_row_number - 1
'THIS MAKES TWO NEW DATAROW OBJECTS
Dim DB_row As DataRow
Dim CSV_row As DataRow
'THIS SETS THE CSV_ROW OBJECT EQUAL TO THE FIRST ROW OF THE CSV DATATABLE
CSV_row = ToLoad.Rows(j)
'THIS SETS DB_ROW EQUAL TO A NEW ROW IN THE DATATABLE MADE FROM THE DATABASE
DB_row = EDITmembers.NewRow()
'THIS SETS ALL OF THE COLUMNS IN THIS NEW ROW AS EQUAL TO THE CORRESPONDING ROW IN THE CSV DATATABLE
DB_row("Contact Name") = CSV_row("Contact Name")
DB_row("Do not mail") = CSV_row("Do not mail")
DB_row("Membership Type") = CSV_row("Membership Type")
DB_row("Street Address") = CSV_row("Street Address")
DB_row("Supplemental Address 1") = CSV_row("Supplemental Address 1")
DB_row("Supplemental Address 2") = CSV_row("Supplemental Address 2")
DB_row("City") = CSV_row("City")
DB_row("Postal Code") = CSV_row("Postal Code")
DB_row("Email") = CSV_row("Email")
DB_row("Phone (primary)") = CSV_row("Phone (primary)")
EDITmembers.Rows.Add(DB_row)
j = j + 1
Loop
'UPDATE THE DATABASE WITH ALL THE CHANGES
mySqlDataAdapter.Update(DBDataset, "MemberList")
MessageBox.Show("done!")
I want to search for the value where item = 'apple' and then add the entire column to a DataGridView in VB.net form application. I use following code lines to do my task, but the output i get is a blank data cell.
Dim table As DataTable = myTable.Tables("fruits")
Dim expression, item As String
expression = "item = 'apple'"
Dim foundRows() As DataRow
foundRows = table.Select(expression)
Dim dt As New DataTable
dt.Columns.Add("ID")
dt.Columns.Add("item")
dt.Columns.Add("price")
Dim row1 As DataRow = dt.NewRow
For Each row As DataRow In foundRows
row1.Item("ID") = row(0)
row1.Item("item") = row(1)
row1.Item("price") = row(2)
Next
dt.Rows.Add(row1)
DataGridView1.DataSource = dt
End Sub
Change your code as this... you should add columns in-order to add rows as u expect
Dim table As DataTable = myTable.Tables("fruits")
Dim expression As String
expression = "item = 'apple'"
Dim foundRows() As DataRow
foundRows = table.Select(expression)
Dim col, col1, col2 As New DataGridViewTextBoxColumn
col.HeaderText = "ID"
col1.HeaderText = "Item"
col2.HeaderText = "Price"
DataGridView1.Columns.Add(col)
DataGridView1.Columns.Add(col1)
DataGridView1.Columns.Add(col2)
For Each row As DataRow In foundRows
DataGridView1.Rows.Add(row(0), row(1), row(2))
Next
You're declaring the row to add once (row1) and looping through foundRows and assigning same var (row1) and then adding it only once to the DG, this will results in adding only the last found item.
Change your code starting from "Dim row1 As DataRow = dt.NewRow" to be:
For Each row As DataRow In foundRows
Dim row1 As DataRow = dt.NewRow
row1.Item("ID") = row(0)
row1.Item("item") = row(1)
row1.Item("price") = row(2)
dt.Rows.Add(row1)
Next
I'm not sure if this is the only reason, but give it a try :)
Fist column of listview is populated from database (database column name KONTO - only values that starts with 2020-), second column of the listview should be populate from corresponding items to KONTO from same database column NAZIV into second column of the listview.
Description is in column NAZIV in databsase
I've been experimenting with this all day and didn't have any success.
Here is the code I have so far :
ListView1.View = System.Windows.Forms.View.Details
ListView1.Columns.Add("COL1", 100, HorizontalAlignment.Left) 'KONTO
ListView1.Columns.Add("COL2", 160, HorizontalAlignment.Left) 'NAZIV
Dim FilePath As String = "W:\GLAVNI\KOR14\"
Dim DBF_File As String = "MATIKGL"
Dim ColName As String = "KONTO"
'Dim naz As String
Using con As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FilePath & _
" ;Extended Properties=dBASE IV")
con.Open()
Using cmd As New OleDbCommand("SELECT * FROM MATIKGL ORDER BY KONTO, NAZIV", con)
Using reader As OleDbDataReader = cmd.ExecuteReader()
If reader.HasRows Then
While (reader.Read())
Me.ListView1.Items.Add(reader("KONTO"))
'LOOP BELOW SELECTS ALL ITEMS THAT STARTS WITH 2020-
For i = 0 To ListView1.Items.Count - 1
If ListView1.Items(i).ToString.Contains("2020-") Then
Else
ListView1.Items.Remove(ListView1.Items(i))
End If
Next
End While
Else
End If
End Using
End Using
con.Close()
End Using
Thanks.
UPDATE
To be more clear, here is the screen from database.
Only items starting with 2020- (1) should populate first column of listview, and second column should be populated with "2020-" description from column NAZIV (2).
Each LV Item has a collection of SubItems associated with it. The subItems show as columns in the Details view:
Dim lvi As ListViewItem ' scratch var for adding items
Dim tmp As String
Using cmd As New OleDbCommand("SELECT * FROM MATIKGL ORDER BY KONTO, NAZIV", con)
Using reader As OleDbDataReader = cmd.ExecuteReader()
If reader.HasRows Then
While (reader.Read())
' Db rdr returns Object, cast to string
tmp = reader.Item("KONTO").ToString
' no need to loop - just use the scratch vars
' only adding if it contains 2020
If tmp.Contains("2020-") Then
lvi = New ListViewItem
lvi.Text = tmp
' add the sub item
lvi.SubItems.Add(reader("NAZIV").toString)
ListView1.Items.Add(lvi)
End If
End While
End If
End Using
you can get rid of the tmp var using reader.Item("KONTO").ToString.Contains("2020")...the above is for clarity
I am trying to retrieve data from SQL Server into my form. I am trying with the below code. When I run this I get the first item or row but I am unable load the rest of the items into my listview . Can someone help to solve my issue?
Sub GetInvoiceDetails()
Dim Inv As New petClass
Dim dt As DataTable = Inv.GetInvoiceDetailsbyNo(txtInvoiceNo.Text)
If dt.Rows.Count > 0 Then
For Each row In dt.Rows
srno += 1
Dim lstitem = Lstview.Items.Add(srno)
lstitem.SubItems.Add(dt.Rows(0).Item("ItemName").ToString)
lstitem.SubItems.Add(dt.Rows(0).Item("SellingPrice".ToString)).ToString()
Next
End If
'clearcontrols
End Sub
You're always using the first row in the DataTable with dt.Rows(0).
Instead:
For Each row As DataRow In dt.Rows
srno += 1
Dim lstitem = Lstview.Items.Add(srno)
lstitem.SubItems.Add(row.Field(of String)("ItemName"))
lstitem.SubItems.Add(row.Field(Of String)("SellingPrice"))
Next
First thing i see is that you're referencing only the first row of your datatable.
Try this:
Sub GetInvoiceDetails()
Dim Inv As New petClass
Dim dt As DataTable = Inv.GetInvoiceDetailsbyNo(txtInvoiceNo.Text)
If dt.Rows.Count > 0 Then
For Each row In dt.Rows
srno += 1
Dim lstitem = Lstview.Items.Add(srno)
lstitem.SubItems.Add(row.Items("ItemName").ToString)
lstitem.SubItems.Add(row.Items("SellingPrice".ToString)).ToString()
Next
End If
'clearcontrols
End Sub
Next thing, I'm a bit confused by what you're trying to do here:
lstitem.SubItems.Add(row.Items("SellingPrice".ToString)).ToString()
You shouldn't need the second ToString(), no??