adding a dataset inside a datareader in vb.net - vb.net

i hope i have asked the question title correctly. let me explain my issue -
i am making a table through vb.net code (htmltablecell, htmltablerow..) no this table populates with an sql query and works perfectly. but inside this table in one tablecell, i need to add a dropdownlist which shall require a completely differernt query and shall run on its own on each row. so the code is as follows
Sql = "..."
rd = ExecuteReader(SqlCnn, Sql)
Dim newcounter As Integer = 0
While rd.Read()
newcounter += 1
Dim tr As New HtmlTableRow
Dim td As New HtmlTableCell
Dim chkbox As New CheckBox
Dim id As String = rd("id") & ""
If id.Length = 0 Then id = "new" & newcounter
id &= "_" & rd("col1")
chkbox.Style.Add("width", "20%")
chkbox.ID = "new_id_" & id
chkbox.Text = rd("col1")
tr.Style.Add("width", "100%")
td.Style.Add("width", "10%")
td.Style.Add("text-align", "left")
td.Controls.Add(chkbox)
tr.Cells.Add(td)
td = New HtmlTableCell
td.Style.Add("width", "30%")
Dim ddl As New dropdownlist
ddl.Style.Add("width", "80%")
ddl.ID = "a1_" & id
--???????
td.Controls.Add(ddl)
tr.Cells.Add(td)
the ??? in the code is where the dropdownlist shall get populated each time with its own datareader and while loop and query. how can i achieve this?

I would do this with 2 queries; 1 to get the ddl data and 1 to get the actual records. Get the ddl data (ddlDataReader) before the actual results, create the ddl object and add it to each row.
Something like this should work: (I don't do VB.Net, so you may need to fix things)
Dim ddl As New dropdownlist
ddl.Style.Add("width", "80%")
ddl.ID = "a1_" & id
While ddlDataReader.Read()
---add items to ddl
end
Dim newcounter As Integer = 0
While rd.Read()
newcounter += 1
Dim tr As New HtmlTableRow
Dim td As New HtmlTableCell
Dim chkbox As New CheckBox
Dim id As String = rd("id") & ""
If id.Length = 0 Then id = "new" & newcounter
id &= "_" & rd("col1")
chkbox.Style.Add("width", "20%")
chkbox.ID = "new_id_" & id
chkbox.Text = rd("col1")
tr.Style.Add("width", "100%")
td.Style.Add("width", "10%")
td.Style.Add("text-align", "left")
td.Controls.Add(chkbox)
tr.Cells.Add(td)
td = New HtmlTableCell
td.Style.Add("width", "30%")
td.Controls.Add(ddl)
tr.Cells.Add(td)
Another approach would be to load the ddl data into a datatable, so that you can loop through it multiple times, and then create the ddl with a unique Id when each row is being created.

Related

Search and replace inside string column in DataTable is slow?

I am fetching distinct words in a string column of a DataTable (.dt) and then replacing the unique values with another value, so essentially changing words to other words. Both approaches listed below work, however, for 90k records, the process is not very fast. Is there a way to speed up either approach?
The first approach, is as follows:
'fldNo is column number in dt
For Each Word As String In DistinctWordList
Dim myRow() As DataRow
myRow = dt.Select(MyColumnName & "='" & Word & "'")
For Each row In myRow
row(fldNo) = dicNewWords(Word)
Next
Next
A second LINQ-based approach is as follows, and is actually not very fast either:
Dim flds as new List(of String)
flds.Add(myColumnName)
For Each Word As String In DistinctWordsList
Dim rowData() As DataRow = dt.AsEnumerable().Where(Function(f) flds.Where(Function(el) f(el) IsNot DBNull.Value AndAlso f(el).ToString = Word).Count = flds.Count).ToArray
ReDim foundrecs(rowData.Count)
Cnt = 0
For Each row As DataRow In rowData
Dim Index As Integer = dt.Rows.IndexOf(row)
foundrecs(Cnt) = Index + 1 'row.RowId
Cnt += 1
Next
For i = 0 To Cnt
dt(foundrecs(i))(fldNo) = dicNewWords(Word)
Next
Next
So you have your dictionary of replacements:
Dim d as New Dictionary(Of String, String)
d("foo") = "bar"
d("baz") = "buf"
You can apply them to your table's ReplaceMe column:
Dim rep as String = Nothing
For Each r as DataRow In dt.Rows
If d.TryGetValue(r.Field(Of String)("ReplaceMe"), rep) Then r("ReplaceMe") = rep
Next r
On my machine it takes 340ms for 1 million replacements. I can cut that down to 260ms by using column number rather than name - If d.TryGetValue(r.Field(Of String)(0), rep) Then r(0) = rep
Timing:
'setup, fill a dict with string replacements like "1" -> "11", "7" -> "17"
Dim d As New Dictionary(Of String, String)
For i = 0 To 9
d(i.ToString()) = (i + 10).ToString()
Next
'put a million rows in a datatable, randomly assign dictionary keys as row values
Dim dt As New DataTable
dt.Columns.Add("ReplaceMe")
Dim r As New Random()
Dim k = d.Keys.ToArray()
For i = 1 To 1000000
dt.Rows.Add(k(r.Next(k.Length)))
Next
'what range of values do we have in our dt?
Dim minToMaxBefore = dt.Rows.Cast(Of DataRow).Min(Function(ro) ro.Field(Of String)("ReplaceMe")) & " - " & dt.Rows.Cast(Of DataRow).Max(Function(ro) ro.Field(Of String)("ReplaceMe"))
'it's a crappy way to time, but it'll prove the point
Dim start = DateTime.Now
Dim rep As String = Nothing
For Each ro As DataRow In dt.Rows
If d.TryGetValue(ro.Field(Of String)("ReplaceMe"), rep) Then ro("ReplaceMe") = rep
Next
Dim ennd = DateTime.Now
'what range of values do we have now
Dim minToMaxAfter = dt.Rows.Cast(Of DataRow).Min(Function(ro) ro.Field(Of String)("ReplaceMe")) & " - " & dt.Rows.Cast(Of DataRow).Max(Function(ro) ro.Field(Of String)("ReplaceMe"))
MessageBox.Show($"min to max before of {minToMaxBefore} became {minToMaxAfter} proving replacements occurred, it took {(ennd - start).TotalMilliseconds} ms for 1 million replacements")

value of type integer cannot be converted to datatable vn.net

i am trying to create tree view and some error i can not fix it
Sub CREATENODE()
Dim TRN As New TreeNode
Dim DT As New DataTable
DT.Clear()
DT = ACCOUNTTableAdapter.TREE_ACCOUNT()
For I As Integer = 0 To DT.Rows.Count - 1
If DT.Rows(I)(9).ToString() = "00000000-0000-0000-0000-000000000000" Then
TRN = New TreeNode(DT.Rows(I)(3).ToString() + " " + DT.Rows(I)(4).ToString())
TRN.Tag = DT.Rows(I)(1).ToString()
If DT.Rows(I)(7).ToString() <> "0" Then
TRN.ImageIndex = 0
TRN.SelectedImageIndex = 0
Else
TRN.ImageIndex = 1
TRN.SelectedImageIndex = 1
End If
TreeView1.Nodes.Add(TRN)
End If
Next
''For Each NODE As TreeNode In TreeView1.Nodes
'' CHELD(NODE)
'Next
End Sub
This is nonsense
Dim TRN As New TreeNode
Dim DT As New DataTable
DT.Clear()
DT = ACCOUNTTableAdapter.TREE_ACCOUNT()
You create a New TreeNode and then inside the loop you overwrite it with another New one. Just put the Dim inside the loop after the if.
Dim TRN = New TreeNode($"{row(3)} {row(4)}")
You create a brand new DataTable. Then you clear it when it can't possibly have anything in it. Then you throw it away and assign a different DataTable to it.
Just do
Dim DT = ACCOUNTTableAdapter.TREE_ACCOUNT()
I have simplified your code by using a For Each loop. Also, I used and interpolated string indicated by the $ preceding the string. Variables can be inserted in place surrounded by braces { }.
As far as the actual problem, you need to create an instance of your table adapter with the New keyword. Then call the appropriate method. A simple application will just use .GetData.
Private Sub CREATENODE()
Dim DT = (New ACCOUNTTableAdapter).TREE_ACCOUNT() 'See what intellisense offers. It may be just .GetData
For Each row As DataRow In DT.Rows
If row(9).ToString() = "00000000-0000-0000-0000-000000000000" Then
Dim TRN = New TreeNode($"{row(3)} {row(4)}")
TRN.Tag = row(1)
If row(7).ToString() <> "0" Then
TRN.ImageIndex = 0
TRN.SelectedImageIndex = 0
Else
TRN.ImageIndex = 1
TRN.SelectedImageIndex = 1
End If
TreeView1.Nodes.Add(TRN)
End If
Next
End Sub
Hint: Why not put the entire row in the Tag property. You will have access to all the fields by casting the Tag back to a DataRow.

Crystal Reports empty when printed during runtime(without viewer)

I'm developing a small POS system using VB.Net , MS Sql and Crystal Reports. I have no trouble viewing reports using Cry Rep Viewer. But when i try to print a bill during runtime the report becomes empty. Following is the sequence i'm executing within the procedure.
Generate bill no
Deduct qty from stocks
add the transaction from temp table to final sales table
print bill
delete temp table transactions
clear for next transaction
But my problem comes during the bill printing. Bill does not pickup the necessary records from the sales table. Following is my code for the end transaction. (I am using few of my own methods and functions which are from another class and im also using a fix bill no for testing)
I'm also attaching 2 bills. First 1 is the one viewed and exported from the Cry Report Viewer. The second one is the one with problem, and its empty even though the records exists in the table. Can some one kindly advice me on this matter?
Private Sub endCurrentTransaction()
Try
Dim sqlTempBill As String = "SELECT * FROM tb_transactions where cur_user='" & curUser & "'"
Dim sqlSales As String = "SELECT * FROM tb_sales where bill_no=''"
'Get Bill No
Dim newBillNo As String = generateBillNo()
'Deduct IT qty
Dim tempBill As DataTable
tempBill = myTbClass.myFunctionFetchTbData(sqlTempBill)
Dim i As Integer = 0
Dim curQty As Double = 0
Dim trQty As Double = 0
Dim updatedQty As Double = 0
For i = 0 To tempBill.Rows.Count - 1
curQty = 0
'Get the Current stock qty
Dim sqlgetCurQty As String = "SElECT cur_qty FROM tb_stock where it_batch_code='" & tempBill.Rows(i).Item("it_batch_code") & "'"
conn.Open()
Dim SqlCmdCurQty As New SqlCommand(sqlgetCurQty, conn)
Dim DataReadercurQty As SqlDataReader = SqlCmdCurQty.ExecuteReader
While DataReadercurQty.Read()
curQty = DataReadercurQty.Item(0)
End While
DataReadercurQty.Close()
conn.Close()
trQty = tempBill.Rows(i).Item("qty")
updatedQty = curQty - trQty
Dim sqlUpdateQtyString As String = "UPDATE tb_stock SET cur_qty=" & Math.Round((updatedQty), 3) & " Where it_batch_code='" & tempBill.Rows(i).Item("it_batch_code") & "'"
conn.Open()
Dim SqlCmdQty As New SqlCommand(sqlUpdateQtyString, conn)
SqlCmdQty.ExecuteNonQuery()
conn.Close()
'add to sales
Dim tempTbSales As DataTable
tempTbSales = myTbClass.myFunctionFetchTbData(sqlSales)
Dim dataRow As DataRow = tempTbSales.NewRow
dataRow("it_code") = Trim(tempBill.Rows(i).Item("it_code"))
dataRow("it_batch_code") = Trim(tempBill.Rows(i).Item("it_batch_code"))
dataRow("it_name") = Trim(tempBill.Rows(i).Item("it_name"))
dataRow("buy_price") = Math.Round(tempBill.Rows(i).Item("buy_price"), 3)
dataRow("sell_price") = Math.Round(tempBill.Rows(i).Item("sell_price"), 3)
dataRow("qty") = Math.Round(tempBill.Rows(i).Item("qty"), 3)
dataRow("gross_val") = Math.Round(tempBill.Rows(i).Item("gross_val"), 3)
dataRow("discount_val") = Math.Round(tempBill.Rows(i).Item("discount_val"), 3)
dataRow("net_val") = Math.Round(tempBill.Rows(i).Item("net_val"), 3)
dataRow("profit_profile") = Trim(tempBill.Rows(i).Item("profit_profile"))
dataRow("discount_profile") = Trim(tempBill.Rows(i).Item("discount_profile"))
dataRow("cus_name") = Trim(tempBill.Rows(i).Item("cus_name"))
dataRow("tr_type") = Trim(cmbTrans.Text)
dataRow("cr_card_type") = Trim(cmbCardType.Text)
dataRow("card_no") = Trim(txtCardNo.Text)
dataRow("bill_no") = newBillNo
dataRow("discount_profile") = Trim(tempBill.Rows(i).Item("cus_name"))
dataRow("cur_user") = curUser
dataRow("added_date") = curServerDateTime
tempTbSales.Rows.Add(dataRow)
Call myTbClass.MyMethodUpdateTable(sqlSales, tempTbSales)
Next
i = 0
'Print bill
Dim cash, balance As Double
Dim crepBill As New repBill
crepBill.SetDatabaseLogon("sa", dbPwd)
cash = Val(Me.txtCash.Text)
balance = Val(Me.txtBalance.Text)
crepBill.RecordSelectionFormula = "{TB_SALES.bill_no} ='" & "000015" & "'"
crepBill.DataDefinition.FormulaFields("txtCash").Text = Format(cash, "#0.00")
crepBill.DataDefinition.FormulaFields("txtBal").Text = Format(balance, "#0.00")
crepBill.PrintToPrinter(1, False, 0, 0)
crepBill.Dispose()
'delete temp bill table
For i = 0 To tempBill.Rows.Count - 1
tempBill.Rows(i).Delete()
Next
Call myTbClass.MyMethodUpdateTable(sqlTempBill, tempBill)
'reset front end
Call loadBill()
Call clearCurrentTransaction()
Call clearCurrentSubTotals()
Call clearCurCashBalance()
'Íncrease the bill no by 1
Call increaseBillNo()
txtItCode.Focus()
Catch ex As Exception
MsgBox("This error was generated at endCurrentTransaction()")
End Try
End Sub
I found out that report need to be refreshed before printing. Report will only take data if it is refreshed.
https://answers.sap.com/answers/13088178/view.html

How do I loop through the rows in a Dataview in vb.net

I need to loop through the rows in a DataView so I can get the data or object from the row to add to a listbox. Here is my code for the DataView. The RowFilter is set to only extract the data for a row if the ID that the user entered matches the "CustomerID" field. How do I loop through the Rows that have been added to create a temporary object for the data in the row?
'create new table for storing incident data
Dim incidentTable As DataView = CType(incidentsDataSource.Select(
DataSourceSelectArguments.Empty), DataView)
incidentTable.RowFilter = ("CustomerID = '" & custIDTextBox.Text & "'")
Dim incidentRow As DataRowView = incidentTable(0)
'declare temporary incident and store all data in corresponding fields
Dim incident As New Incident
With incident
.IncidentID = incidentRow("IncidentID").ToString
.CustomerID = incidentRow("CustomerID").ToString
.ProductCode = incidentRow("ProductCode").ToString
.TechID = incidentRow("TechID").ToString
.DateOpened = incidentRow("DateOpened").ToString
.DateClosed = incidentRow("DateClosed").ToString
.Title = incidentRow("Title").ToString
End With
The DataView itself IS a list; a list of DataRowView objects to be precise. You simply loop through the DataView itself, e.g.
For Each row As DataRowView In myDataView
Dim name = CStr(row("Name"))
'...
Next

Best way to merge two Datatables

I need to marge two datatables with condition. I have a datatable where the data comes from a local XML Database and another datatable where the data comes from a remote SQL Server.
If any update made in the remote datatable I need to update/merge with the local datatable. Here is what I have so far:
Public Sub MargeTwoTable()
Dim SQL As String = ""
Dim RemoteTable As New DataTable
Dim LocalTable As DataTable
Dim dal As New DalComon
Dim yy As Integer = 0
Dim UpdateDate As String
Dim TableName As String = "V_Book_Price"
LocalTable = LoadDataTable(TableName, True)
UpdateDate = LocalTable.Compute("MAX(update_date)", Nothing)
SQL = "select * from V_Book_Price where Update_Date > '" & UpdateDate & "'"
RemoteTable = dal.GetDataSetBySQL(SQL).Tables(0)
If RemoteTable.Rows.Count > 0 Then
For i = 0 To RemoteTable.Rows.Count - 1
Dim st As DataRow
Dim mm() As DataRow = LocalTable.Select("ID = '" & RemoteTable.Rows(i).Item("ID") & "'")
If mm.Length = 0 Then
st = LocalTable.NewRow
For yy = 0 To RemoteTable.Columns.Count - 1
st(yy) = RemoteTable.Rows(i)(yy)
Next
LocalTable.Rows.Add(st)
Else
st = mm(0)
For yy = 0 To RemoteTable.Columns.Count - 1
If IsDate(RemoteTable.Rows(i)(yy)) Then
st(yy) = CDate(RemoteTable.Rows(i)(yy)).ToString("s")
Else
st(yy) = RemoteTable.Rows(i)(yy)
End If
Next
mm = Nothing
End If
Next
End If
End Sub
In this code data comes from the remote database which updates a date getter then the local database . Both tables have "ID" as the primary key. The code is working well, but the problem is that when more than 1000 records are updated this function takes too long using loops.
Not sure if can be applicable, but have you ever looked at the
DataTable.LoadDataRow() method?.
It seems a good candidate to substitute all of you code above.
Your code could be simplified to these lines
Dim row as DataRow
For Each row in RemoteTable.Rows
LocalTable.LoadDataRow(row.ItemArray, false)
Next
Another alternative could be the DataTable.Merge that could cut your code to a single line
LocalTable.Merge(RemoteTable, False)
However, the real effectiveness of these two methods depends on the schema compatibility and from the presence of AutoNumber (identity) columns.