Export datatable to crystal report - vb.net

I created a datatable (.xsd) that corresponds to the datatable I coded in the code-behind.
Protected Sub btnDproceed_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDproceed.Click
'---> ASSUME THAT I CODES FOR THE FIRST FOUR COLUMNS OF DATATABLE IS MADE HERE
'---> CREATE DYNAMIC COLUMNS OF SCORES
cn.Open()
'---> SQL COMMAND HERE THAT GET TOP 5 DATA FROM DATABASE USED TO GENERATE 5 ADDITIONAL COLUMNS IN dt
rs = cmd.ExecuteReader
Do While rs.Read
Dim gwno As String = rs.Item("GWNO").ToString
If gwno.Length = 1 Then
gwno = "0" & gwno
End If
Dim vHeader As String = "LES" & gwno & "_" & rs.Item("GWTYPE")
If Not dt.Columns.Contains(vHeader) Then
Dim f As New Data.DataColumn(vHeader, GetType(System.String))
dt.Columns.Add(f)
f.AllowDBNull = True
End If
Loop
cn.Close()
'---> DATA ROWS FOR SCORES
For Each row As DataRow In dt.Rows
If Not dt.Columns.Contains("RANK") Then
dt.Columns.Add("RANK").SetOrdinal(0)
End If
Dim v As Integer
v = v + 1
row(0) = v.ToString
For col As Integer = 4 To dt.Columns.Count - 1
'---> SQL COMMAND THAT GETS DATA (score) BASED ON THE 5 GENERATED COLUMNS ABOVE
rs = cmd.ExecuteReader
If rs.Read = True Then
If Not String.IsNullOrEmpty(rs.Item("SCORE").ToString) Then
row(col) = rs.Item("SCORE").ToString
Else
row(col) = rs.Item("REMTYPE").ToString
End If
End If
cn.Close()
Next
Next
'---> ADDITIONAL STATIC COLUMNS
dt.Columns.Add("LE_SUM")
dt.Columns.Add("LE_CNT")
dt.Columns.Add("LE_AVE")
dt.Columns.Add("UE_SUM")
dt.Columns.Add("UE_CNT")
dt.Columns.Add("UE_AVE")
dt.Columns.Add("AVERAGE")
dt.Columns.Add("CGRADE")
dt.Columns.Add("+/-GPTS")
dt.Columns.Add("CRANK")
dt.Columns.Add("DEF")
dt.Columns.Add("EXPTD")
dt.Columns.Add("ABCNT")
dt.Columns.Add("INC")
Dim crpt As New ReportDocument()
CrystalReportViewer1.DisplayGroupTree = False
crpt.Load(Server.MapPath("~/CrystalReport.rpt"))
crpt.SetDataSource(dt)
CrystalReportViewer1.ReportSource = crpt
End Sub
As seen above, the dt and Scores.xsd has similar datacolumns which will be used in generating the crystal report (yes, it's working). But the problems are the Top 5 columns and it's corresponding data. In Scores.xsd, DataColumn5 to DataColumn9 and DataColumn24 to DataColumn28 can't generate data in Crystal Report since in datatable dt, there's no same name datacolumns. Now, how can I make there columns in Crystal Report since these columns are changing depending on the Top 5.

Related

Moving rows up and down in a datagridview and updating the database

I have a datagridview and I am getting all the data from a sql database I want to be able to move rows from one position to the other either up or down and it should also reflect the same in the database.
Currently this is what I have done and it does move the items as desired ( am adding 100 to the value of the column that am using to move up and subtracting 100 when moving down) but the problem with this is that if it find that the value of the next item in the row is lower, it doesnt move or if you add 100 then its value suddenly becomes more that 3 items above it, it doesnt move to the next position instead it moves 3 positions up, how can I simplify it to make it move just 1 row above or below respectively.
Private Sub BntMoveUp_Click(sender As Object, e As EventArgs) Handles BntMoveUp.Click
For i As Integer = 0 To DataGridView2.Rows.Count() - 1
Dim c As Boolean
c = DataGridView2.Rows(i).Cells(0).Value
' if the checkbox cell is checked
If c = True Then
' MessageBox.Show("Checked")
Dim cid As Integer = DataGridView2.Rows(i).Cells(1).Value
Dim cid2 As Integer = DataGridView2.Rows(i - 1).Cells(1).Value
Str = "update Production..CMBGSeat_Staging set [Priority] =[Priority] > 1 where cid=" & cid
updaterecords(Str)
Dim cmd As Odbc.OdbcCommand
Dim LDataadapter As Odbc.OdbcDataAdapter
Dim MyDataset As DataSet
Dim insert As String
con()
insert = "select * from Production..CMBGSeat_Staging where DateCompleted is null order by Priority desc"
cmd = New Odbc.OdbcCommand(insert, sqlcon)
LDataadapter = New Odbc.OdbcDataAdapter
LDataadapter.SelectCommand = cmd
MyDataset = New DataSet
' MyDataset = New DataSet
LDataadapter.Fill(MyDataset)
DataGridView2.DataSource = MyDataset.Tables(0)
' if not
Else
' MessageBox.Show("Not Checked")
End If
Next
End Sub
Private Sub BtnMoveDown_Click(sender As Object, e As EventArgs) Handles BtnMoveDown.Click
For i As Integer = 0 To DataGridView2.Rows.Count() - 1
Dim c As Boolean
c = DataGridView2.Rows(i).Cells(0).Value
'If the Then checkbox cell Is checked
If c = True Then
' MessageBox.Show("Checked")
Dim cid As Integer = DataGridView2.Rows(i).Cells(1).Value
Dim cid2 As Integer = DataGridView2.Rows(i + 1).Cells(1).Value
Str = "update Production..CMBGSeat_Staging set [Priority] =[Priority] < 1 where cid=" & cid
updaterecords(Str)
Dim cmd As Odbc.OdbcCommand
Dim LDataadapter As Odbc.OdbcDataAdapter
Dim MyDataset As DataSet
Dim insert As String
con()
insert = "select * from Production..CMBGSeat_Staging where DateCompleted is null order by Priority desc"
cmd = New Odbc.OdbcCommand(insert, sqlcon)
LDataadapter = New Odbc.OdbcDataAdapter
LDataadapter.SelectCommand = cmd
MyDataset = New DataSet
MyDataset = New DataSet
LDataadapter.Fill(MyDataset)
DataGridView2.DataSource = MyDataset.Tables(0)
' if not
Else
'MessageBox.Show("Not Checked")
End If
Next
End Sub

how to make a datagridview cellvaluechange 2 column which trigged loop

I am developing a sales order application. I am using a datagridview to fill the sales order.
the field in my datagridview are as per below
ItemCode - ItemDescription - qty - price
The description field is a combobox.
What I want is that when a user input an ItemCode, it automatically check my database and give me the Itemdescription
I also want user to be able to select an item from the ItemDescription which is a combobox, and it wil automatically update my Itemcode.
Private Sub salesorder_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles salesorder_dgv.CellValueChanged
If salesorder_dgv.Rows.Count > 0 Then
If e.ColumnIndex = 0 Then
Dim READER As SqlDataReader
conn.Open()
Dim query As String
query = "select * from item where code = '" & salesorder_dgv.Rows(e.RowIndex).Cells(0).Value & "'"
cmd = New SqlCommand(query, conn)
READER = cmd.ExecuteReader
If READER.Read Then
salesorder_dgv.Rows(e.RowIndex).Cells(1).Value = READER.GetString(2)
End If
conn.Close()
End If
If e.ColumnIndex = 1 Then
Dim READER As SqlDataReader
conn.Open()
Dim query As String
query = "select * from item where description = '" & salesorder_dgv.Rows(e.RowIndex).Cells(1).Value & "'"
cmd = New SqlCommand(query, conn)
READER2 = cmd.ExecuteReader
If READER.Read Then
salesorder_dgv.Rows(e.RowIndex).Cells(0).Value = READER.GetString(1)
End If
conn.Close()
End If
End If
End Sub
Is there a way to make this code work? i am getting "The Connection was not closed"
There's a lot wrong there so I'll first address what you have to clean it up, then address how you should be doing it.
As suggested in the comments, you should be creating all your ADO.NET objects where you need them, including the connection. You create, use and destroy in the narrowest scope possible. Also, if you only want data from a single column, don't use SELECT *. Retrieve only the column(s) you need. As you're only retrieving data from one column of one row, you should be using ExecuteScalar rather than ExecuteReader.
Next, you should acquaint yourself with the DRY principle, i.e. Don't Repeat Yourself. You have two blocks of code there that are almost identical so you should extract out the common parts and write that only once and pass in the different parts.
Finally, don't use string concatenation to insert values into SQL code. ALWAYS use parameters. It avoids a number of issues, most importantly SQL injection, which is quite possible in your case, as the user is entering free text. With all that in mind, the code you have would be refactored like so:
Private Sub salesorder_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles salesorder_dgv.CellValueChanged
If salesorder_dgv.RowCount > 0 Then
Dim sourceColumnIndex = e.ColumnIndex
Dim targetColumnIndex As Integer
Dim query As String
Select Case sourceColumnIndex
Case 0
targetColumnIndex = 1
query = "SELECT description FROM item WHERE code = #param"
Case 1
targetColumnIndex = 0
query = "SELECT code FROM item WHERE description = #param"
Case Else
Return
End Select
Dim row = salesorder_dgv.Rows(e.RowIndex)
Dim sourceValue = row.Cells(sourceColumnIndex).Value
Using connection As New SqlConnection("connection string here"),
command As New SqlCommand(query, connection)
command.Parameters.AddWithValue("#param", sourceValue)
connection.Open()
row.Cells(targetColumnIndex).Value = command.ExecuteScalar()
End Using
End If
End Sub
Now to how you should have done it. If you're populating a combo box column with all the descriptions then you must be querying the database for them in the first place. What you should have done is retrieved both the descriptions and the codes in that initial query. That way, you never have to go back to the database. You can populate a DataTable with both the codes and the descriptions and then much of the work will be done for you.
For the example below, I started by setting up the form in the designer, which meant adding and configuring the appropriate columns in the grid and adding the BindingSource components. That also includes setting the DataPropertyName property of each grid column so it binds to the appropriate source column. I'm also manually populating the item data here but you would be getting that data from your database.
Private itemTable As New DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadItemData()
LoadSaleData()
End Sub
Private Sub LoadItemData()
With itemTable.Columns
.Add("code", GetType(String))
.Add("description", GetType(String))
End With
With itemTable.Rows
.Add("123", "First Item")
.Add("abc", "Second Item")
.Add("789", "Third Item")
.Add("xyz", "Fourth Item")
.Add("01a", "Fifth Item")
End With
itemBindingSource.DataSource = itemTable
With itemDescriptionColumn
.DisplayMember = "Description"
.ValueMember = "Description"
.DataSource = itemBindingSource
End With
End Sub
Private Sub LoadSaleData()
Dim saleTable As New DataTable
With saleTable.Columns
.Add("ItemCode", GetType(String))
.Add("ItemDescription", GetType(String))
.Add("Quantity", GetType(Integer))
.Add("Price", GetType(Decimal))
End With
saleBindingSource.DataSource = saleTable
salesorder_dgv.DataSource = saleBindingSource
End Sub
Private Sub salesorder_dgv_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles salesorder_dgv.CellValidating
If e.RowIndex >= 0 AndAlso
e.ColumnIndex = 0 AndAlso
Not String.IsNullOrEmpty(e.FormattedValue) Then
'Check that the code entered by the user exists.
e.Cancel = (itemBindingSource.Find("code", e.FormattedValue) = -1)
If e.Cancel Then
MessageBox.Show("No such item")
End If
End If
End Sub
Private Sub salesorder_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles salesorder_dgv.CellValueChanged
Dim rowIndex = e.RowIndex
Dim sourceColumnIndex = e.ColumnIndex
If rowIndex >= 0 And sourceColumnIndex >= 0 Then
Dim sourceColumnName As String
Dim targetColumnName As String
Dim targetColumnIndex As Integer
Select Case sourceColumnIndex
Case 0
sourceColumnName = "code"
targetColumnName = "description"
targetColumnIndex = 1
Case 1
sourceColumnName = "description"
targetColumnName = "code"
targetColumnIndex = 0
Case Else
Return
End Select
Dim itemRow = itemBindingSource(itemBindingSource.Find(sourceColumnName, salesorder_dgv(sourceColumnIndex, rowIndex).Value))
Dim code = CStr(itemRow(targetColumnName))
salesorder_dgv(targetColumnIndex, rowIndex).Value = code
End If
End Sub
You start by populating the items and binding that data to the combo box column and then create an empty DataTable for the sales and bind that to the grid. The code checks that any manually entered codes actually do match items and it will set the description when a code is entered manually and the code when a description is selected from the list. It does this by referring back to the BindingSource containing the item data each time, so no extra queries. You might want to consider retrieving the price data for each item too, and calculating the price for that row based on that and the quantity.

DataGridView moves rows to bottom when cell is updated with Unbound data

I have a DataGridView that is styled with code and is using data from a SQLite Database
The Database is NOT bound to the DataGridView. A number of events are triggered when I click on a row.
First the Database is updated with today's date.
And the cell that contain's that date reflects the change.
I then call a sort on the column based on the cells value. With this code
dgvLinks.Sort(dgvLinks.Columns(3), ListSortDirection.Ascending)
The process works as expected with no issues IF I omit these lines of code from the Sub Routine ViewSearches() that populates the DataGridView.
If rowCount <= 25 Then
maxRowCount = 25 - rowCount
For iA = 1 To maxRowCount
dgvLinks.Rows.Add(" ")
Next
End If
I can use these empty rows if I make a call to repopulate the DataGridView with ViewSearches()
I am trying to avoid this design as it seems like a over use of resource.
The ERROR that is happening is the 4 rows that contain data are moved to the bottom of the DataGridView and above these 4 rows with data are the empty rows. I will post the relevant code below.
My question How can I keep the empty rows and populate DataGridView so the rows with data are at the top of the DataGridView?
Here is a Screen Shot after I selected LID 2. It is updated and bubbled to the bottom of the DGV.
Private Sub ViewSearches()
Dim intID As Integer
Dim strChannelName As String
Dim strLinkAddress As String
Dim strLastVisit As String
Dim strLinkType As String
Dim rowCount As Integer
Dim maxRowCount As Integer
'Dim emptyStr As String = " "
Using conn As New SQLiteConnection($"Data Source = '{gv_dbName}';Version=3;")
conn.Open()
Using cmd As New SQLiteCommand("", conn)
'cmd.CommandText = "SELECT * FROM LinkTable"
' Line of CODE Above works with If statement in While rdr
'==========================================================
'cmd.CommandText = "SELECT * FROM LinkTable WHERE ytSiteType = 'News'"
cmd.CommandText = "SELECT * FROM LinkTable WHERE ytSiteType = #site"
cmd.Parameters.Add("#site", DbType.String).Value = gvSLT
Using rdr As SQLite.SQLiteDataReader = cmd.ExecuteReader
'dgvLinks.DataSource = rdr
'Statement Above use when DB is bound to dgvLinks
'=================================================
While rdr.Read()
intID = CInt((rdr("LID")))
strChannelName = rdr("ytChannelName").ToString
strLinkAddress = rdr("ytLinkAddress").ToString
strLastVisit = rdr("ytLastVisit").ToString
strLinkType = rdr("ytSiteType").ToString
'If strLinkType = gvSLT Then
dgvLinks.Rows.Add(intID, strChannelName, strLinkAddress, strLastVisit)
rowCount = rowCount + 1
'End If
End While
dgvLinks.Sort(dgvLinks.Columns(3), ListSortDirection.Ascending)
End Using
If rowCount <= 25 Then
maxRowCount = 25 - rowCount
For iA = 1 To maxRowCount
dgvLinks.Rows.Add(" ")
Next
End If
End Using
End Using
'FindEmpty()
End Sub
Click Event with Update to Database
Private Sub dgvLinks_CellClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvLinks.CellClick
selRow = e.RowIndex
If e.RowIndex = -1 Then
gvalertType = "4"
frmAlert.ShowDialog()
Exit Sub
End If
'Dim col As DataGridViewColumn = Me.dgvLinks.Columns(e.ColumnIndex)
Dim row As DataGridViewRow = Me.dgvLinks.Rows(e.RowIndex)
If row.Cells(2).Value Is Nothing Then
gvalertType = "5"
frmAlert.ShowDialog()
Return
Exit Sub
ElseIf gvTxType = "View" Then
webPAGE = row.Cells(2).Value.ToString()
siteID = CInt(row.Cells(0).Value.ToString())
UpdateSiteData()
''MsgBox("Stop " & selRow)
'dgvLinks.ClearSelection()
'dgvLinks.Refresh()
'dgvLinks.RefreshEdit()
Process.Start(webPAGE)
'dgvLinks.Columns.Clear()
''dgvLinks.Rows.Clear()
''ViewSearches()
ElseIf gvTxType = "Delete" Or gvTxType = "Update" Then
gvID = CInt(row.Cells(0).Value)
gvSiteName = row.Cells(1).Value.ToString
gvSiteURL = row.Cells(2).Value.ToString
frmADE.Show()
Close()
End If
End Sub
Update Routine
Public Sub UpdateSiteData()
Dim dateToday = Date.Today
dateToday = CDate(CDate(Date.Today).ToString("M-d-yyyy"))
Using conn As New SQLiteConnection($"Data Source = '{gv_dbName}';Version=3;"),
cmd As New SQLiteCommand("UPDATE LinkTable SET ytLastVisit = #ytLastVisit WHERE LID =" & siteID, conn)
conn.Open()
cmd.Parameters.Add("#ytLastVisit", DbType.String).Value = dateToday.ToString("M-d-yyyy")
cmd.ExecuteNonQuery()
dgvLinks.Rows(selRow).Cells(3).Value = dateToday.ToString("M-d-yyyy")
'Line of code above INSERTS value in Last Visit Column at the correct ROW
'NOT needed if you reload data from the database
'=========================================================================
'dgvLinks.Refresh()
'dgvLinks.RefreshEdit()
dgvLinks.Sort(dgvLinks.Columns(3), ListSortDirection.Ascending)
End Using
End Sub
You will see a number of things I have tried commented out.
As I said I can FIX the issue if I make a call to the ViewSearches() Sub Routine.
Private Sub StyleDGV()
'Sets Design of the DataGridView
'===============================
dgvLinks.DefaultCellStyle.Font = New Font("Times New Roman", 13.0F, FontStyle.Bold)
dgvLinks.ColumnCount = 4
dgvLinks.Columns(0).Width = 60 'ID
dgvLinks.Columns(1).Width = 325 'Site Name 325
dgvLinks.Columns(2).Width = 860 'Site Url 860
dgvLinks.Columns(3).Width = 154 'LastVisit 140
'Option with no blank rows increase col count to 5
'OR increase width of col(3) WHY? because the scroll bar is not showing
' TOTAL Width 1450 Height 488
'=============================
'To Set Col Header Size Mode = Enabled
'To Set Col Header Default Cell Styles DO in Properties
'dgvLinks.Columns(6).DefaultCellStyle.Format = "c"
dgvLinks.ColumnHeadersHeight = 10 'Sans Serif 'Tahoma
dgvLinks.ColumnHeadersDefaultCellStyle.Font = New Font("Sans Serif", 12.0F, FontStyle.Bold)
dgvLinks.ColumnHeadersDefaultCellStyle.ForeColor = Color.Blue
dgvLinks.DefaultCellStyle.BackColor = Color.LightGoldenrodYellow
'DGV Header Names
dgvLinks.Columns(0).Name = "LID"
dgvLinks.Columns(1).Name = "Site Name"
dgvLinks.Columns(2).Name = "Site URL"
dgvLinks.Columns(3).Name = "Last Visit"
dgvLinks.Columns(0).SortMode = DataGridViewColumnSortMode.NotSortable
dgvLinks.Columns(1).SortMode = DataGridViewColumnSortMode.NotSortable
dgvLinks.Columns(2).SortMode = DataGridViewColumnSortMode.NotSortable
dgvLinks.Columns(3).SortMode = DataGridViewColumnSortMode.NotSortable
End Sub
Any one following this question the FIX that permitted keeping the empty rows was to just omit the sort command in the Update to Database Sub Routine
As far as getting the data from the SQLite DB into the grid… you almost have it in the ViewSearches method. The command text looks good; however you are using an SQLiteDataReader. This is resorting to reading the data line by line.
I suggest you use the SQLiteDataAdapter instead. With it you can get the DataTable from the DB in one shot. First create and initialize a DataSet, then create a new SQLiteDataAdapter then add your command to the data adapter something like…
DataSet ds = new DataSet();
using (SQLiteDataAdapter sqlDA = new SQLiteDataAdapter()) {
conn.Open();
sqlDA.SelectCommand = cmd.CommanText;
sqlDA.Fill(ds, “tableName”);
if (ds.Tables.Count > 0) {
//return ds.Tables[“tableName”];
dgvLinks.DataSource = ds.Tables[“tableName”];
}
}
This will add a DataTable to the DataSet ds called “tableName” if the query succeeded.
Then simply use that DataTable as a DataSource to the grid… something like…
dgvLinks.DataSource = ds.Tables[“tableName”];

how to Flip dataset and display in datagridview

I try to flip dataset to display column as rows by using this code but it does not work :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button.Click
Dim ds2 As New DataSet
Dim dt2 As New DataTable
Dim com1 As String = "select col1,col2,col3 from table1"
ds2 = FlipDataSet(ds2)
Dim dp As New SqlDataAdapter(com1, conn)
dp.Fill(dt2)
DGV_lev1.DataSource = dt2.DefaultView
End Sub
and use this function to flip dataset :
Private Function FlipDataSet(old_DataSet As DataSet) As DataSet
Dim ds As New DataSet()
For Each dt As DataTable In old_DataSet.Tables
Dim table As New DataTable()
For i As Integer = 0 To dt.Rows.Count
table.Columns.Add(Convert.ToString(i))
table.Columns(0).ColumnName = "Fields"
If i = 0 Then
Continue For
Else
table.Columns(i).ColumnName = "Customer " & i
End If
Next
Dim r As DataRow
For k As Integer = 0 To dt.Columns.Count - 1
r = table.NewRow()
r(0) = dt.Columns(k).ToString()
For j As Integer = 1 To dt.Rows.Count
r(j) = dt.Rows(j - 1)(k)
Next
table.Rows.Add(r)
Next
ds.Tables.Add(table)
Next
Return ds
End Function
to make datagirdview display from this :
to this :
can anyone help me
thank you
Try this, it worked in a quick test I did:
Private Function Transpose(ByVal table As DataTable) As DataTable
Dim flippedTable As New DataTable
'creates as many columns as rows in source table
flippedTable.Columns.AddRange(
table.Select.Select(
Function(dr) New DataColumn("col" & table.Rows.IndexOf(dr), GetType(Object))
).ToArray)
'iterates columns in source table
For Each dc As DataColumn In table.Columns
'get array of values of column in each row and add as new row in target table
flippedTable.Rows.Add(table.Select.Select(Function(dr) dr(dc)).ToArray)
Next
Return flippedTable
End Function

DataGridView not Refreshing

I have a SQL table that looks similar to this:
1 | a | stuff...
2 | a | stuff...
3 | b | stuff...
4 | a | stuff...
5 | b | stuff...
I only want to show:
3 | b | stuff...
5 | b | stuff...
So I use this code to load the DataGridView:
Private Sub GetData()
Dim objConn As New SqlConnection(sConnectionString)
objConn.Open()
' Create an instance of a DataAdapter.
Dim daInstTbl As _
New SqlDataAdapter("SELECT * FROM Table WHERE Column = 'b'", objConn)
' Create an instance of a DataSet, and retrieve data from the Authors table.
daInstTbl.FillSchema(dsNewInst, SchemaType.Source)
daInstTbl.Fill(dsNewInst)
' Create a new instance of a DataTable
MyDataTable = dsNewInst.Tables(0)
daInstTbl.Update(dsNewInst)
End Sub
Private Sub InitializeDataGridView()
Try
' Set up the DataGridView.
With Me.DataGridView1
' Set up the data source.
.DataSource = MyDataTable
End With
Catch ex As SqlException
MessageBox.Show(ex.ToString, _
"ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
System.Threading.Thread.CurrentThread.Abort()
End Try
End Sub
Everything works great and until I want to delete 3 and renumber 4 and 5 down one to become 3 and 4. I have loops handling everything and the database is receiving the correct data except my DataGridView only shows the updates when I restart the program.
Here's my delete code:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click
Dim objConn As New SqlConnection(sConnectionString)
objConn.Open()
Dim daInstDeleteTbl As New SqlDataAdapter("SELECT * FROM Table", objConn)
Dim dsDeleteInst As New DataSet
Dim MyDeleteTable As DataTable
' Create an instance of a DataSet, and retrieve data from the Authors table.
daInstDeleteTbl.FillSchema(dsDeleteInst, SchemaType.Source)
daInstDeleteTbl.Fill(dsDeleteInst)
' Create a new instance of a DataTable
MyDeleteTable = dsDeleteInst.Tables(0)
'Begin Delete Code
Dim DeleteID, DeleteIndex As Integer
Dim MadeChange As Boolean = False
Integer.TryParse(TextBox1.Text, DeleteID)
Dim dgvIndexCount As Integer = MyDeleteTable.Rows.Count - 1
If MyDeleteTable.Rows(dgvIndexCount).Item(0) > DeleteID Then
Dim counter As Integer = -1
For Each row As DataRow In MyDeleteTable.Rows
counter += 1
If row.Item("Column") = DeleteID Then
DeleteIndex = counter
End If
Next
MadeChange = True
End If
drCurrent = MyDeleteTable.Rows.Find(DeleteID)
drCurrent.Delete()
If MadeChange = True Then
Dim i As Integer = 0
For i = DeleteIndex + 1 To dgvIndexCount
MyDeleteTable.Rows(i).Item(0) = MyDeleteTable.Rows(i).Item(0) - 1
Next
End If
'Send Changes to SQL Server
Dim objCommandBuilder As New SqlCommandBuilder(daInstDeleteTbl)
daInstDeleteTbl.Update(dsDeleteInst)
Dim daInstTbl As _
New SqlDataAdapter("SELECT * FROM Table WHERE Column = 'b'", objConn)
Dim objCommandReBuilder As New SqlCommandBuilder(daInstTbl)
daInstTbl.Update(dsNewInst)
End Sub
I think I am doing a lot of extra work just to do this wrong. Any ideas? Thanks.
When you invoke SqlDataAdapter.Update() the adapter updates the values in the database by executing the respective INSERT, UPDATE, or DELETE (from MSDN). The SELECT command is not executed. So you need to do it like this:
Insert/Update/Delete:
daInstTbl.Update(dsNewInst)
Select:
daInstTbl.Fill(dsNewInst)
Commit:
dsNewInst.AcceptChanges()
Example
Private connection As SqlConnection
Private adapter As SqlDataAdapter
Private data As DataSet
Private builder As SqlCommandBuilder
Private grid As DataGridView
Private Sub InitData()
Me.SqlSelect(firstLoad:=True, fillLoadOption:=LoadOption.OverwriteChanges, acceptChanges:=True)
Me.grid.DataSource = Me.data
Me.grid.DataMember = "Table"
End Sub
Public Sub SaveData()
Me.SqlInsertUpdateAndDelete()
Me.SqlSelect(fillLoadOption:=LoadOption.OverwriteChanges, acceptChanges:=True)
End Sub
Public Sub RefreshData(preserveChanges As Boolean)
Me.SqlSelect(fillLoadOption:=If(preserveChanges, LoadOption.PreserveChanges, LoadOption.OverwriteChanges))
End Sub
Private Sub SqlSelect(Optional firstLoad As Boolean = False, Optional ByVal fillLoadOption As LoadOption = LoadOption.PreserveChanges, Optional acceptChanges As Boolean = False)
If (firstLoad) Then
Me.data = New DataSet()
Me.connection = New SqlConnection("con_str")
Me.adapter = New SqlDataAdapter("SELECT * FROM Table WHERE Column = 'b'", connection)
Me.builder = New SqlCommandBuilder(Me.adapter)
End If
Me.connection.Open()
If (firstLoad) Then
Me.adapter.FillSchema(Me.data, SchemaType.Source, "Table")
End If
Me.adapter.FillLoadOption = fillLoadOption
Me.adapter.Fill(Me.data, "Table")
If (acceptChanges) Then
Me.data.Tables("Table").AcceptChanges()
End If
Me.connection.Close()
End Sub
Private Sub SqlInsertUpdateAndDelete()
If (Me.connection.State <> ConnectionState.Open) Then
Me.connection.Open()
End If
Me.adapter.Update(Me.data, "Table")
Me.connection.Close()
End Sub
PS: (Untested code)
My solution was to change the way I was declaring variables. Before I had:
Dim daInstTbl As _
New SqlDataAdapter("SELECT * FROM Table WHERE Column = 'b'", objConn)
The affect was that recalling the subroutine ignored this line because the variable daInstTbl was already declared previously. The solution was:
' Delete old instance of a Data____ classes
da = Nothing
ds = Nothing
dt = Nothing
If GetAll = False Then
da = New SqlDataAdapter(sSelCmd, objConn)
Else
da = New SqlDataAdapter(sSelAllCmd, objConn)
End If
' Create an instance of a DataSet, and retrieve data from the Authors table.
ds = New DataSet
da.FillSchema(ds, SchemaType.Source)
da.Fill(ds)
This cleared the information and allowed me to assign a new value. My subroutines serve double duty by assigning two query strings and then using an optional boolean to determine which version to use.
Dim sSelCmd As String = "SELECT * FROM Table WHERE Coloumn= 'b'"
Dim sSelAllCmd As String = "SELECT * FROM Table"
Private Sub GetData(Optional ByVal GetAll As Boolean = False)
Dim objConn As New SqlConnection(sConnectionString)
objConn.Open()
And that leads into the code above! Thanks for the help. Some of your concepts got my thoughts turning in the right direction and motivated me to clean up my code into a much more readable form.