Best way to merge two Datatables - vb.net

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.

Related

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

Evaluate string on record table,

How to evaluate match on the record table with vb I have a code like this
Dim absenperintah As SqlCommand = New SqlCommand("Select * from mytable where kodetp ='109'", cekdata)
absenperintah.CommandType = CommandType.Text
cekdata.Open()
Dim valuex = "500"
Using cekbaca As SqlDataReader =
absenperintah.ExecuteReader(CommandBehavior.CloseConnection)
If cekbaca.Read = True Then
Dim nilxbaca = cekbaca("rumus_k") --> record in the table is 1906650*(3.7/100)
Dim nilmy = valuex + nilxbaca
Dim result = New DataTable().Compute(nilmy, Nothing)
MsgBox(result)
End If
cekbaca.Close()
End Using
cekdata.Close()
I get the result 185,070,546 it should be result =70,564.55
how to get result =70,564.55 from Dim nilHy = valuex + nilxbaca
Your problem is that you are declaring these numbers as strings and they are being calculated accordingly.
What you think you are doing:
500 + 1906650*(3.7/100) = 70,564.55
If you were processing these as numbers, it would perform math and your calculation would work.
However, you have declared these values as strings. Therefore the code is actually running like this:
"500" + "1906650*(3.7/100)" 'String concatenation. Not math.
5001906650*(3.7/100) = 185,070,546
Try this code instead:
Dim absenperintah As SqlCommand = New SqlCommand("Select * from mytable where kodetp ='109'", cekdata)
absenperintah.CommandType = CommandType.Text
cekdata.Open()
Dim valuex = "500"
Using cekbaca As SqlDataReader =
absenperintah.ExecuteReader (CommandBehavior.CloseConnection)
If cekbaca.Read = True Then
Dim nilxbaca = cekbaca("rumus_k") 'record in the table is "1906650*(3.7/100)"
Dim nilmy = valuex & " + " & nilxbaca 'makes "500 + 1906650*(3.7/100)"
'Note: your next line of code, DataTable.Compute() will evaluate a
' (string) formula over several rows.
Dim result = New DataTable().Compute(nilmy, Nothing)
'Based on this code here, you are only processing one row.
'Maybe .Compute() is totally unnecessary here.
'You would be better to say: result = 500 + nilxbaca
' or maybe declare valuex as integer, to help the compiler treat it like a number instead of a string.
' or maybe your original code did apply this formula over several rows.
' ... In that case, my example would fix your Compute() formula.
MsgBox(result)
End If
cekbaca.Close()
End Using
cekdata.Close()

get column names Jet OLE DB in vb.net

I've written a function which reads csv files and parametrizes them accordingly, therefore i have a function gettypessql which queries sql table at first to get data types and therefore to adjust the columns which are later inserted in sql. So my problem is when I set HDR=Yes in Jet OLE DB I get only column names like F1, F2, F3. To circumvent this issue I've set HDR=No and written some for loops but now I get only empty strings, what is actually the problem? here is my code:
Private Function GetCSVFile(ByVal file As String, ByVal min As Integer, ByVal max As Integer) As DataTable
Dim ConStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & TextBox1.Text & ";Extended Properties=""TEXT;HDR=NO;IMEX=1;FMT=Delimited;CharacterSet=65001"""
Dim conn As New OleDb.OleDbConnection(ConStr)
Dim dt As New DataTable
Dim da As OleDb.OleDbDataAdapter = Nothing
getData = Nothing
Try
Dim CMD As String = "Select * from " & _table & ".csv"
da = New OleDb.OleDbDataAdapter(CMD, conn)
da.Fill(min, max, dt)
getData = New DataTable(_table)
Dim firstRow As DataRow = dt.Rows(0)
For i As Integer = 0 To dt.Columns.Count - 1
Dim columnName As String = firstRow(i).ToString()
Dim newColumn As New DataColumn(columnName, mListOfTypes(i))
getData.Columns.Add(newColumn)
Next
For i As Integer = 1 To dt.Rows.Count - 1
Dim row As DataRow = dt.Rows(i)
Dim newRow As DataRow = getData.NewRow()
For j As Integer = 0 To getData.Columns.Count - 1
If row(j).GetType Is GetType(String) Then
Dim colValue As String = row(j).ToString()
colValue = ChangeEncoding(colValue)
colValue = ParseString(colValue)
colValue = ReplaceChars(colValue)
newRow(j) = colValue
Else
newRow(j) = row(j)
End If
Next
getData.Rows.Add(newRow)
Application.DoEvents()
Next
Catch ex As OleDbException
MessageBox.Show(ex.Message)
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
dt.Dispose()
da.Dispose()
End Try
Return getData
End Function
and get types sql, this one doesn't convert properly, especially doubles
Private Sub GetTypesSQL()
If (mListOfTypes Is Nothing) Then
mListOfTypes = New List(Of Type)()
End If
mListOfTypes.Clear()
Dim dtTabelShema As DataTable = db.GetDataTable("SELECT TOP 0 * FROM " & _table)
Using dtTabelShema
For Each col As DataColumn In dtTabelShema.Columns
mListOfTypes.Add(col.DataType)
Next
End Using
End Sub
I think you have made it more complicated than it needs to be. For instance, you get the dbSchema by creating an empty DataTable and harvesting the Datatypes from it. Why not just use that first table rather than creating a new table from the Types? The table also need not be reconstructed over and over for each batch of rows imported.
Generally since OleDb will try to infer types from the data, it seems unnecessary and may even get in the way in some cases. Also, you are redoing everything that OleDB does and copying data to a different DT. Given that, I'd skip the overhead OleDB imposes and work with the raw data.
This creates the destination table using the CSV column name and the Type from the Database. If the CSV is not in the same column order as those delivered in a SELECT * query, it will fail.
The following uses a class to map csv columns to db table columns so the code is not depending on the CSVs being in the same order (since they may be generated externally). My sample data CSV is not in the same order:
Public Class CSVMapItem
Public Property CSVIndex As Int32
Public Property ColName As String = ""
'optional
Public Property DataType As Type
Public Sub New(ndx As Int32, csvName As String,
dtCols As DataColumnCollection)
CSVIndex = ndx
For Each dc As DataColumn In dtCols
If String.Compare(dc.ColumnName, csvName, True) = 0 Then
ColName = dc.ColumnName
DataType = dc.DataType
Exit For
End If
Next
If String.IsNullOrEmpty(ColName) Then
Throw New ArgumentException("Cannot find column: " & csvName)
End If
End Sub
End Class
The code to parse the csv uses CSVHelper but in this case the TextFieldParser could be used since the code just reads the CSV rows into a string array.
Dim SQL = String.Format("SELECT * FROM {0} WHERE ID<0", DBTblName)
Dim rowCount As Int32 = 0
Dim totalRows As Int32 = 0
Dim sw As New Stopwatch
sw.Start()
Using dbcon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(SQL, dbcon)
dtSample = New DataTable
dbcon.Open()
' load empty DT, create the insert command
daSample = New MySqlDataAdapter(cmd)
Dim cb = New MySqlCommandBuilder(daSample)
daSample.InsertCommand = cb.GetInsertCommand
dtSample.Load(cmd.ExecuteReader())
' dtSample is not only empty, but has the columns
' we need
Dim csvMap As New List(Of CSVMapItem)
Using sr As New StreamReader(csvfile, False),
parser = New CsvParser(sr)
' col names from CSV
Dim csvNames = parser.Read()
' create a map of CSV index to DT Columnname SEE NOTE
For n As Int32 = 0 To csvNames.Length - 1
csvMap.Add(New CSVMapItem(n, csvNames(n), dtSample.Columns))
Next
' line data read as string
Dim data As String()
data = parser.Read()
Dim dr As DataRow
Do Until data Is Nothing OrElse data.Length = 0
dr = dtSample.NewRow()
For Each item In csvMap
' optional/as needed type conversion
If item.DataType = GetType(Boolean) Then
' "1" wont convert to bool, but (int)1 will
dr(item.ColName) = Convert.ToInt32(data(item.CSVIndex).Trim)
Else
dr(item.ColName) = data(item.CSVIndex).Trim
End If
Next
dtSample.Rows.Add(dr)
rowCount += 1
data = parser.Read()
If rowCount = 50000 OrElse (data Is Nothing OrElse data.Length = 0) Then
totalRows += daSample.Update(dtSample)
' empty the table if there will be more than 100k rows
dtSample.Rows.Clear()
rowCount = 0
End If
Loop
End Using
End Using
End Using
sw.Stop()
Console.WriteLine("Parsed and imported {0} rows in {1}", totalRows,
sw.Elapsed.TotalMinutes)
The processing loop updates the DB every 50K rows in case there are many many rows. It also does it in one pass rather than reading N rows thru OleDB at a time. CsvParser will read one row at a time, so there should never be more than 50,001 rows worth of data on hand at a time.
There may be special cases to handle for type conversions as shown with If item.DataType = GetType(Boolean) Then. A Boolean column read in as "1" cant be directly passed to a Boolean column, so it is converted to integer which can. There could be other conversions such as for funky dates.
Time to process 250,001 rows: 3.7 mins. An app which needs to apply those string transforms to every single string column will take much longer. I'm pretty sure that using the CsvReader in CSVHelper you could have those applied as part of parsing to a Type.
There is a potential disaster waiting to happen since this is meant to be an all-purpose importer/scrubber.
For i As Integer = 0 To dt.Columns.Count - 1
Dim columnName As String = firstRow(i).ToString()
Dim newColumn As New DataColumn(columnName, mListOfTypes(i))
getData.Columns.Add(newColumn)
Next
Both the question and the self-answer build the new table using the column names from the CSV and the DataTypes from a SELECT * query on the destination table. So, it assumes the CSV Columns are in the same order that SELECT * will return them, and that all CSVs will always use the same names as the tables.
The answer above is marginally better in that it finds and matches based on name.
A more robust solution is to write a little utility app where a user maps a DB column name to a CSV index. Save the results to a List(Of CSVMapItem) and serialize it. There could be a whole collection of these saved to disk. Then, rather than creating a map based on dead reckoning, just deserialize the desired for user as the csvMap in the above code.

.Conversion error on unique identifier, shouldn't be referenced at all?

I'm working on the shopping cart for a website, I have this function that retrieves a voucher from my database:
Public Shared Function CheckForVoucher(ByVal strVoucherName As String) As DataTable
Dim connect As New SqlConnection
Dim Data As New DataTable ''Connection works, finds number of Vouchers in DB that match either code or ID. ID to be used for randomly generated vouchers.
connect.ConnectionString = "SERVER = SERVER-SQL01; Trusted_Connection=yes; DATABASE=PCSQL"
connect.Open()
Dim query As String
Dim search As String
search = strVoucherName
If search.Length >= 25 Then
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE vID='" & search & "' "
Else
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE voucherName='" & search & "' "
End If
Dim command = New SqlDataAdapter(query, connect)
command.Fill(Data)
connect.Close()
strVoucherName = query
Return Data
End Function
This all works peachy-keen on the site I'm working on. At the end of a customers order it fires another function, the increase the totalUses of the voucher by one (my boss wants to make sure that people don't spam the codes and run him out of business).
Public Shared Function addUse(ByVal strVoucherName As String, intCurrentUses As Integer) As Boolean
Dim connect As New SqlConnection
Dim data As New DataTable
connect.ConnectionString = "SERVER = SERVER-SQL01; Trusted_Connection = yes; DATABASE=PCSQL"
connect.Open()
Dim query As String
Dim name As String = strVoucherName
Dim current As Integer = intCurrentUses
Dim newint As Integer = current + 1
query = "UPDATE dbo.X_WW_VOUCHER_DETAILS SET currentUses= #currentUses WHERE voucherName=#voucherName"
Dim command As New SqlCommand(query, connect)
command.Parameters.Add("#voucherName", SqlDbType.VarChar)
command.Parameters("#voucherName").Value = name
command.Parameters.Add("#currentUses", SqlDbType.Int)
command.Parameters("#currentUses").Value = newint
command.ExecuteNonQuery()
connect.Close()
Return True
End Function
This also works fine, and I can check the SQL table in SQL SERVER and see that the "currentUses" column has increased by one. Yay.
Problem
When I test the code by submitting again, it fails if the currentUses column is equal to the validUses column. I end up the error "Conversion failed when converting from a character string to uniqueidentifier" even though the Unique Identifier is not directly referenced at all.
I've tested on a voucher that is valid 5 times. Times 1 through 4, no errors but as soon as currentUses was also 5... no go.
Why would equal columns cause my function to crap itself?
SQL Table
-vID Uniqueidentifier
-voucherName Nchar(15)
-expiryDate Date
-validUses Int
-currentUses Int
-discountType Nchar(15)
-appliesTo Nchar(15)
-numberOf Nchar(20)
-Amount Int
-noOfItems Int
-Category Nchar(100)
-freebieID Nchar(15)
-discountAmount Int
-Description Nchar(255)
EDIT
I have narrowed the error down to this if statement.
If search.Length >= 25 Then
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE vID='" & search & "' "
Else
query = "SELECT * from PCSQL.dbo.X_WW_VOUCHER_DETAILS WHERE voucherName='" & search & "' "
End If
The Voucher itself is called from cart.aspx using
Protected Sub btnVoucherCheck_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnVoucherCheck.Click
Dim Data As DataTable = Voucher.CheckForVoucher(txtVoucher.text)
If Data.Rows.Count > 0 Then
Dim row As DataRow
row = Data.Rows(0)
Voucher.VoucherID = row.Item("vID").ToString().Trim()
Voucher.VoucherName = row.Item("voucherName").ToString().Trim()
Voucher.ExpiryDate = row.Item("ExpiryDate")
Voucher.ValidUses = row.Item("ValidUses")
Voucher.CurrentUses = row.Item("CurrentUses")
Voucher.DiscountType = row.Item("DiscountType").ToString().Trim()
Voucher.AppliesTo = row.Item("AppliesTo").ToString().Trim()
Voucher.NumberOf = row.Item("NumberOf").ToString().Trim()
Voucher.Amount = row.Item("Amount")
Voucher.noOfItems = row.Item("NoOfItems")
Voucher.Category = row.Item("Category").ToString().Trim()
Voucher.FreebieID = row.Item("FreebieID").ToString().Trim()
Voucher.DiscountAmount = row.Item("DiscountAmount")
Dim count As Int32
count = 0
Dim expiry As DateTime = Voucher.ExpiryDate
Dim today As DateTime = Date.Today()
count = ((expiry - today).Days)
If count <= -1 Then
txtVoucher.Text = "Voucher expired"
Else 'Further checks. One: Valid uses against current uses, checks if too many people have used the voucher.
If (Voucher.CurrentUses >= Voucher.ValidUses) Then
txtVoucher.Text = "Sorry, Voucher is no longer valid"
Else 'Redirects to one of three methods based on discount type.
c.VoucherName = Voucher.VoucherName
If c.discounted = True Then
For Each item As RepeaterItem In rptCart.Items
Dim quantity As TextBox = CType(item.FindControl("txtQuantity"), TextBox)
Dim ProductID As HyperLink = CType(item.FindControl("hlProductID"), HyperLink)
Dim lblPrice As Label = CType(item.FindControl("lblPrice"), Label)
lblPrice.Text = Product.GetProductPrice(ProductID.Text, quantity.Text, c)
Next
End If
Select Case Voucher.DiscountType
Case "Dollar"
txtVoucher.Text = "$ Not yet Supported"
Case "Percentage"
percentageDiscount()
Case "Freebie"
txtVoucher.Text = "Freebie Not Yet Supported"
Case Else
txtVoucher.Text = "Not working."
End Select
End If
End If
Else
End If
End Sub
The two relevant columns are compared in the middle of this function, but my code doesn't execute that far if they are equal to being with. I get the conversion error referencing the line in my CheckForVoucher function that I pasted above. It can't be my comparison that causes the error because the DataTable I use for that doesn't fully exist at the point the error occurs.
The problem you have is when the value of search is 25 characters or longer, you are passing it into the database to compare with the vID column. That column is a uniqueidentifier which means it's a GUID in C# terms. If the value you pass in cannot be converted directly to a GUID, then you will get a conversion error.

adding a dataset inside a datareader in 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.