I am using a datagridview to display table data and changing values of a particular cell. Depending on requirement I may need to change such values for more than one row.
I am trying to use datagridview1.CellValueChanged to populate a Dataset (i.e. create a collection of changes made) and subsequently saving the changes by clicking on a command button.
My problem is that though for each change, the sub is being called ONLY the last change is being saved. I was thinking of using the Dataset to store multiple records where the values are changed and then SAVE all the rows in the Dataset in the database table (using Update).
Could there be some solution to my predicament.
PS. Before trying this (ADO.net dataset) I was updating a temporary table and then using that I was updating the database.
Grateful for a solution please.
Code:::
Private Sub dGridVwCreaCode_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dGridVwCreaCode.CellValueChanged
Dim qryStr_CodeShtText_Changed As String
Dim var_CodeID_Changed As Long
var_CodeID_Changed = dGridVwCreaCode(e.ColumnIndex - 2, e.RowIndex).Value
qryStr_CodeShtText_Changed = "SELECT Code_ID, Code, Code_Descrip FROM Code_SAP " & _
"WHERE (Code_SAP.Code_ID = " & var_CodeID_Changed & ")"
var_CodeShtText_Changed = dGridVwCreaCode(e.ColumnIndex, e.RowIndex).Value.ToString
If Not CatGenieConnPublic.State = ConnectionState.Open Then
CatGenieConnPublic.Open()
End If
da_CodeShtText_Changed = New OleDb.OleDbDataAdapter(qryStr_CodeShtText_Changed, CatGenieConnPublic)
da_CodeShtText_Changed.Fill(ds_CodeShtText_Changed, "Code_SAP")
cb_CodeShtText_changed = New OleDb.OleDbCommandBuilder(da_CodeShtText_Changed)
ds_CodeShtText_Changed.Tables("Code_SAP").Rows(1).Item("Code_Descrip") = var_CodeShtText_Changed
To save the changes (following sub being called from a Button_Click):
Private Sub Save_Changed_CodeShtText()
da_CodeShtText_Changed.Update(ds_CodeShtText_Changed, "Code_SAP")
MsgBox("Changes saved to database....", vbOKOnly + vbInformation)
If CatGenieConnPublic.State = ConnectionState.Open Then
CatGenieConnPublic.Close()
End If
'SET BOOLEAN TO FALSE AS CHANGED VALUES HAVE BEEN SAVED
bool_CellVal_HasChanged = False
End Sub
PS. Somehow I am not able to place all the code lines together, pl pardon me.
What I was missing out on was incrementing the "row" count in the code line:
ds_CodeShtText_Changed.Tables("Code_SAP").Rows(rowNum_Increment - 1).Item("Code_Descrip") = var_CodeShtText_Changed
So every time the user changes data in the particular cell, rows number in incremented by "1" and is collected in the dataset.
Related
It's mostly in the title...
I'm using VB (obviously, see below), but I'm a total beginner with visual studio.
Here is the test code I'm using (it is a simple test button I designed to test the problem I have in the code elsewhere):
Private Sub Test_Click(sender As Object, e As EventArgs) Handles Test.Click
Dim FDBdataset As New FDBDataSet()
Dim FDBTableAdapter As New FDBDataSetTableAdapters.T_PicturesTableAdapter
For Each row As DataRow In FDBTableAdapter.GetData()
row.BeginEdit()
If row("id").ToString = 58672.ToString Then
row.BeginEdit()
Console.Write("Previous Value = " & row("ImgFileName").ToString)
row("ImgFileName") = "Tagada"
row.EndEdit()
Console.WriteLine(", Current Row Value = " & row("ImgFileName").ToString & " - HasChanges : " & FDBdataset.HasChanges())
End If
Next
FDBTableAdapter.Update(FDBdataset)
The output in the console is:
Previous Value = Aphidecta_obliterata_58672, Current Row Value = Tagada - HasChanges : False
I don't understand what is wrong and how to correct it...
I would be very grateful for some help here !
TableAdapter seems set up correctly, and I can read from it, parse rows; display field values, etc...
Update method reports as being correctly set up by the datasource designer.
Code runs without errors but does not affect the DB content.
Why would you think that FDBdataset has any changes in it? Where are you making any changes to it? You have this:
For Each row As DataRow In FDBTableAdapter.GetData()
and GetData returns a new DataTable, so you're making change to that DataTable completely independent of FDBdataset. Use one or the other but not both.
Based on the code you have there, you don't need the DataSet. You can just use the DataTable returnd by GetData:
Dim adapter As New FDBDataSetTableAdapters.T_PicturesTableAdapter
Dim table = FDBTableAdapter.GetData()
For Each row In table
If row.id = 58672 Then
row.ImgFileName = "Tagada"
End If
Next
adapter.Update(table)
Notice that I tidied up your code a lot too. If you're going to use a typed DataSet then use it.
If you actually do need a DataSet for some reason then make the changes to it, not an unrelated DataTable:
Dim data As New FDBDataSet
Dim adapter As New FDBDataSetTableAdapters.T_PicturesTableAdapter
adapter.Fill(data)
For Each row In data.T_Pictures
If row.id = 58672 Then
row.ImgFileName = "Tagada"
End If
Next
adapter.Update(data)
That second code snippet may need some adjustments but I think it should work.
So, the moral of the story is that the Fill method populates an existing DataTable, which can be part of a DataSet but doesn't have to be, while the GetData method creates a new DataTable, populates it and returns it. That new DataTable is not part of any DataSet.
VB.net app changes values in a datagridview programmatically. The values are all as they should be, but the save routine (dtShipments is the datatable that is the source for the datagridview)
Dim dtChanges As DataTable = dtShipments.getchanges()
If more than one has changed, dtChanges is always missing the last row.
In the routine that changes the cell values, I have tried DatagridView1.EndEdit and DatagridView1.CommitEdit, but the behavior is the same. I even tried adding a SendKeys.Send(vbTab) line, since hitting the tab key when making the changes manually is enough to get all the changes to show up in .GetChanges.
What am I missing?
code per request:
Private Sub btnAssign_Click(sender As Object, e As EventArgs) Handles btnAssign.Click
strModErr = "Form1_btnAssign_Click"
Dim sTruck As String = ""
Try
sTruck = Me.DataGridView2.SelectedCells(0).Value.ToString
For Each row As DataGridViewRow In DataGridView1.SelectedRows
row.Cells("Truck").Value = sTruck
Next
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
Catch ex As Exception
WriteErrorToLog(Err.Number, strModErr + " - " + Err.Description)
End Try
End Sub
Private Function SaveChanges() As Boolean
strModErr = "Form1_SaveChanges"
Dim Conn As New SqlConnection(My.Settings.SQLConnectionString)
Dim sSQL As String = "UPDATE fs_Shipments SET Truck = #Truck, Stop = #Stop WHERE SalesOrder = #SO"
Dim cmd As New SqlCommand(sSQL, Conn)
Dim sSO, sTruck As String
Dim iStop As Integer = 0
Try
DataGridView1.EndEdit()
DataGridView1.ClearSelection()
Dim dtChanges As DataTable = dtShipments.getchanges() 'DataRowState.Modified
If Not dtChanges Is Nothing Then
Conn.Open()
For Each row As DataRow In dtChanges.Rows
sSO = row("SalesOrder").ToString
sTruck = row("Truck").ToString
iStop = CInt(row("Stop").ToString)
With cmd.Parameters
.Clear()
.AddWithValue("#SO", sSO)
.AddWithValue("#Truck", sTruck)
.AddWithValue("#Stop", iStop)
End With
cmd.ExecuteNonQuery()
Next
End If
Return True
Catch ex As Exception
WriteErrorToLog(Err.Number, strModErr + " - " + Err.Description)
Return False
End Try
End Function
I am not exactly 100% sure why this happens. The problem appears to be specific to when the user “selects” the cells in the first grid, and then calls the SaveChanges code “BEFORE” the user has made another selection in the first grid. In other words, if the user “selects” the rows to “assign” the truck to in grid 1, then, “AFTER” the “selected” cells have been filled with the selected truck, THEN, the user selects some other cell in grid 1, THEN calls the save changes code. In that case the code works as expected.
All my attempts at committing the changes, either failed or introduced other issues. I am confident a lot of this has to do with the grids SelectedRows collection. IMHO, this looks like a risky way to set the cell values, I would think a more user-friendly approach may be to add a check box on each row and assign the truck values to the rows that are checked. But this is an opinion.
Anyway, after multiple attempts, the solution I came up with only further demonstrates why using a BindingSource is useful in many ways. In this case, it appears the DataTable is not getting updated with the last cell change. Again, I am not sure “why” this is, however since it appears to work using a BindingSource, I can only assume it has something to do with the DataTable itself. In other words, before the “Save” code is executed, we could call the tables AcceptChanges method, but then we would lose those changes. So that is not an option.
To help, below is a full (no-fluff) example. In the future, I highly recommend you pull out the parts of the code that do NOT pertain to the question. Example, all the code that saves the changes to the DB is superfluous in relation to the question… so remove it. The more unnecessary code you add to your question only increases the number of SO users that will “ignore” the question. If you post minimal, complete and working code that reproduces the problem so that users can simply copy and paste without having to add addition code or remove unnecessary code will increase you chances of getting a good answer. Just a heads up for the future.
The solution below simply adds a BindingSource. The BindingSource’s DataSource is the DataTable dtShipments then the BindingSource is used a DataSource to DataGridView1. Then in the SaveChanges method, “before” the code calls the dtShipment.GetChanges() method, we will call the BindingSources.ResetBinding() method which should complete the edits to the underlying data source, in this case the DataTable dtShipments.
If you create a new VS-VB winforms solution, drop two (2) grids and two (2) buttons onto the form as shown below, then change the button names to “btnAssign” and “btnApplyChanges.” The assign button will add the selected truck in grid two to the selected rows in grid one. The apply changes button simply resets the binding source and displays a message box with the number of rows that were changed in the dtShipments DataTable. It should be noted, that the code calls the dtShipments.AcceptChanges() method to clear the changes. Otherwise, the code will update changes that have already been made.
Dim dtShipments As DataTable
Dim dtTrucks As DataTable
Dim shipBS As BindingSource
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtShipments = GetShipmentsDT()
shipBS = New BindingSource()
shipBS.DataSource = dtShipments
dtTrucks = GetTrucksDT()
dtShipments.AcceptChanges()
DataGridView1.DataSource = shipBS
DataGridView2.DataSource = dtTrucks
End Sub
Private Function GetShipmentsDT() As DataTable
Dim dt = New DataTable()
dt.Columns.Add("ID", GetType(String))
dt.Columns.Add("Truck", GetType(String))
dt.Rows.Add(1)
dt.Rows.Add(2)
dt.Rows.Add(3)
dt.Rows.Add(4)
Return dt
End Function
Private Function GetTrucksDT() As DataTable
Dim dt = New DataTable()
dt.Columns.Add("Truck", GetType(String))
For index = 1 To 10
dt.Rows.Add("Truck" + index.ToString())
Next
Return dt
End Function
Private Sub btnAssign_Click(sender As Object, e As EventArgs) Handles btnAssign.Click
Dim sTruck = DataGridView2.SelectedCells(0).Value.ToString
'Dim drv As DataRowView
For Each row As DataGridViewRow In DataGridView1.SelectedRows
'drv = row.DataBoundItem
'drv("Truck") = sTruck
row.Cells("Truck").Value = sTruck
Next
'DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
'shipBS.ResetBindings(True)
'DataGridView1.CurrentCell = DataGridView1.Rows(0).Cells(0)
End Sub
Private Function SaveChanges() As Boolean
Try
shipBS.ResetBindings(True)
Dim dtChanges As DataTable = dtShipments.GetChanges()
If (dtChanges IsNot Nothing) Then
MessageBox.Show("There are " & dtChanges.Rows.Count & " rows changed in the data table")
' update sql DB
dtShipments.AcceptChanges()
End If
Return True
Catch ex As Exception
Return False
End Try
End Function
Private Sub btnApplyChanges_Click(sender As Object, e As EventArgs) Handles btnApplyChanges.Click
Dim ChangesMade As Boolean
ChangesMade = SaveChanges()
End Sub
Lastly, since you are using VB… I highly recommend that you set the “Strict” option to “ON.” When this option is ON, it will flag possible errors that you may be missing. To do this for all future VB solutions, open VS, close any solutions that may be open, then go to Tools->Options->Projects and Solutions->VB Defaults, then set “Option Strict” to “On.” The default setting is off.
I hope this makes sense and helps.
I'm doing this for first time and I need some guidance. I have Datagridviews set to It's datasource. Now how do I properly Update or Insert records to DB from It?
My questions:
Currently I dont have any buttons under Datagridviews (like Add/Remove/Update - do I need them without doubt or is It possible to handle all actions without them ? - I don't use TableAdapterManager !)
MERGE statement - can It be used to compare certain Table with Datagridview and perform Update or Insert on same Table?
If doing INSERT or UPDATE manually, what goes first and how to check what must be done ?
I allready have a code for doing both, but It doesn't work as It should, problem is that I have only 1 button for saving data on form - and that button should Insert or Update data in DB from 2 Datagridviews + Databinded Textboxes on form. So basically there are 3 Tables that can be Updated/Inserted on same form - Datagridviews show related data and Databinded Texboxes show master Table record.
Any help much appreciated.
EDIT (here is my complete code - first loading data into form and Datagrid, then code for Btn_Save):
Imports System.Data
Imports Oracle.DataAccess.Client ' ODP.NET Oracle managed provider
Imports Oracle.DataAccess.Types
Imports System.IO
Imports System
Imports System.Windows.Forms
Imports System.ComponentModel
Public Class Form2
Private da, da1 As OracleDataAdapter
Private cb, cb1 As OracleCommandBuilder
Private ds, ds1 As DataSet
Public OpenedForm1 As Form1 'required for obtaining record ID - this form opens when user double clicks on datagridview record
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BtnSave.Enabled = False 'for eliminating errors when using dataset Update (Oracle recommendation)
Dim SQL1 As String = "SELECT * from TABLE1 WHERE ID_Table1=" & OpenedForm1.DataGridView1.CurrentRow.Cells(0).Value.ToString
Dim DGV1_SQL As String = "SELECT ID_TABLE2, ID_TABLE1, Name, Surname, WHERE ID_TABLE1=" & OpenedForm1.DataGridView1.CurrentRow.Cells(0).Value.ToString
Dim DGV2_SQL As String = "SELECT TABLE3.SERIAL, TABLE3.MODEL," _
& " TABLE3.TYPE FROM TABLE3 INNER JOIN (TABLE1 INNER JOIN TABLE1_TABLE3 ON TABLE1.ID_Table1=TABLE1_TABLE3.ID_Table1_FK) ON " _
& "TABLE3.ID_Table3=TABLE1_TABLE3.ID_Table3_FK WHERE TABLE1_TABLE3.ID_TABLE1_FKK=" & Openedform1.DataGridView1.CurrentRow.Cells(0).Value.ToString
Try
Oracleconn()
'Then I do all DB queries and display results on form
'For SQL1 Databind all textboxes – this is a master record on form
'For DGV2_SQL and DGV2_SQL fill datasets and set Datagrids to datasource
'I'm also hiding all primary key fields and bounding datagrids to Binding sources to enable Binding navigators under them.
End Sub
Private Sub BtnSave_Click(sender As Object, e As EventArgs) Handles BtnSave.Click
'First I assign some variables for Oracle parameters, such as dealing with Null Date values
Oracleconn() 'My connection to DB
Using cmd As OracleCommand = New OracleCommand()
cmd.Connection = Oracleconn()
cmd.Parameters.Clear()
'Adding a lot of paramters here for master record like this...
cmd.Parameters.Add(New OracleParameter("ID", TxtID.Text))
))
'Only Update for master record – Textboxes on form – works just fine
cmd.CommandText = "UPDATE TABLE1" _
& " SET ID_TABLE1= : id .etc
If Not (TxtSerial.Text = "" Or TxtInventar.Text = "11111" Or TxtInventar.TextLength < 9) Then
cmd.ExecuteNonQuery()
cmd.Parameters.Clear()
'Then checking 1st datagridview for data in It
For Each row As DataGridViewRow In DGV1.Rows
If row.Cells(1).Value <> Nothing Then
'Adding parameters again
'Then my attempt for doing update or Insert with MERGE – doesn't work
cmd.CommandText = "MERGE INTO TABLE2 v" _
& "USING (SELECT * FROM TABLE2 WHERE ID_TABLE2='" & row.Cells(1).Value & "') u" _
& " ON u.ID_TABLE2" _
& " WHEN MATCHED THEN UPDATE SET all fields except ID's " _
' & " WHEN NOT MATCHED BY v" _
' & " THEN INSERT... all fields" _
' & " VALUES.... from parameters"
cmd.ExecuteNonQuery()
cmd.Parameters.Clear()
'This was used before, but ofcourse It only updates
da.Update(ds.Tables(0))
BtnSave.Enabled = True
Else
MsgBox("You cannot save without 1st field empty !")
Exit For
End If
Next
'Then check for next Datagrid – this one is hard, It's a joined Table(entitity) from Table1 and Table3, with showing data from that joined Table too
For Each row As DataGridViewRow In DGV2.Rows
'Adding parameters and just performing update – didn't start the Insert so far
MsgBox("Saved.", MsgBoxStyle.Information, "Editing records")
'Refresh Datagridview in Form1 - which is also opened
OpenedForm1.BtnSearch()
Else
MsgBox("1st field is required to be filled If you want to save.", MsgBoxStyle.Exclamation, "Editing records")
End If
End Using
OracleClose() 'close my connection
End Sub
You basically need to do inserts first, then updates, then deletes. You must insert parents before children and, unless your foreign keys cascade deletes, delete children before parents. For updates, it doesn't matter the order. E.g.
Dim parentAdapter As SqlDataAdapter
Dim childAdapter As SqlDataAdapter
Dim data As DataSet
Dim parentTable As DataTable
Dim childTable As DataTable
'...
Dim parentInserts = parentTable.GetChanges(DataRowState.Added)
Dim parentUpdates = parentTable.GetChanges(DataRowState.Modified)
Dim parentDeletes = parentTable.GetChanges(DataRowState.Deleted)
Dim childInserts = childTable.GetChanges(DataRowState.Added)
Dim childUpdates = childTable.GetChanges(DataRowState.Modified)
Dim childDeletes = childTable.GetChanges(DataRowState.Deleted)
If parentInserts IsNot Nothing Then
parentAdapter.Update(parentInserts)
End If
If childInserts IsNot Nothing Then
childAdapter.Update(childInserts)
End If
If parentUpdates IsNot Nothing Then
parentAdapter.Update(parentUpdates)
End If
If childUpdates IsNot Nothing Then
childAdapter.Update(childUpdates)
End If
If childDeletes IsNot Nothing Then
childAdapter.Update(childDeletes)
End If
If parentDeletes IsNot Nothing Then
parentAdapter.Update(parentDeletes)
End If
data.AcceptChanges()
Let Me answer you to the best and honest way as I can because honestly I did that before.
I will answer based on what I used Prog. Lang. and Database and Luckily VB.Net is my Language and MySQL is the database.
My Answers: (Order by your question)
1.Your asking if you need them? For me Yes! because i did that, Think of a form with a DatagridView (Populated with Data) and 3 Buttons (Add,Update,Delete)
Button: Add will save all your datagridview data in table. You see some link or tutorials here
Button: Edit will update specific data based on what you selected you can see it here. What I did is transfer them to textboxes and do the update.
Button: Delete will delete the data based on your selected row actully the link from button update will be your guide you will just edit it and the Delete Query
2.10000% YES! see this the output of that is to put color in datagridview if both of them are the same. (Sounds exiting? Love it :D)
3.Doing manualy would be hard for me so my tip here is why dont you edit your datagridview then do the Update Command Datagridview is editable but Pls provide atleast 1 column that will not be updated because it is the basis of your where clause
So there you go I said everything I know and it will depend on you on what you should follow so good luck and happy coding
Remember : Theres no wrong in coding One Output Tons of ways to execute
I am trying to user ReportViewer to run a report with a dataset filled from a datagridview. I can populate the dataset but I when I run the report, it's only showing the first row. I have done countless hours of searching on this and nothing seems to work.
I have make sure =First(...) was removed from my report field expression
I think the problem has something to do with the XML for the dataset but I am not very familiar with it.
This is just an example, once I figure this out I can transfer my knowledge to my actual project.
Here's what I have:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
dgv.Columns.Add("FirstName", "First Name")
dgv.Columns.Add("LastName", "Last Name")
dgv.Rows.Add("John", "Smith")
dgv.Rows.Add("Jane", "Doe")
createData()
End Sub
Private Sub createData()
Dim dt As New DataTable("namesTable")
dt.Columns.Add("FirstName")
dt.Columns.Add("LastName")
For Each row As DataGridViewRow In dgv.Rows
dt.Rows.Add(row.Cells(0).Value, row.Cells(1).Value)
MsgBox(row.Cells(0).Value & " " & row.Cells(1).Value)
Next
MsgBox(dt.Rows.Count)
DataSet1.Tables.Add(dt)
MsgBox(DataSet1.GetXml)
Dim DSReport As New ReportDataSource()
DSReport.Name = "DataSet1"
DSReport.Value = DataSet1.Tables("namesTable")
ReportViewer.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Local
ReportViewer.LocalReport.ReportEmbeddedResource = "Report1.rdlc"
ReportViewer.LocalReport.DataSources.Clear()
ReportViewer.LocalReport.DataSources.Add(DSReport)
ReportViewer.LocalReport.Refresh()
ReportViewer.RefreshReport()
End Sub
As I'm adding to the dt, my MsgBox message shows me, correctly, my two names.
The MsgBox dt count is 2 so my two names added.
The Dataset XML shows this, which I think is the problem but I don't know how to fix it:
DataSet1 XML
The report then shows:
ReportViewer
Thanks for any help, this is driving me crazy.
Thanks!
It looks like your datasource is not right, why not just use your dataset that you just created. This code works for me:
ReportViewerHeader.LocalReport.DataSources.Clear()
Dim rds As New Microsoft.Reporting.WebForms.ReportDataSource("namesTable", dt)
ReportViewerHeader.LocalReport.ReportPath = "Report1.rdlc"
ReportViewerHeader.LocalReport.DataSources.Add(rds)
ReportViewerHeader.DataBind()
ReportViewerHeader.LocalReport.Refresh()
I am new on DevExpress. I retrieve data from database to gridview and can display them so far. However, I have a button which makes several modifications when user clicks on it.
I can remove the selected row from gridview.
So my obvious question is how can I delete selected rows from database in gridview.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim cevap As DialogResult = DevExpress.XtraEditors.XtraMessageBox.Show("Are you sure?", "Dikkat!", MessageBoxButtons.YesNo)
If cevap = Windows.Forms.DialogResult.No Then Exit Sub
Dim command As New SqlCommand()
command.Connection = spcc.SqlCon
'command.CommandText = "DELETE FROM EBARPARAMETER WHERE ID = '" & GridView1.what? & "' "
Dim read As SqlDataReader
read = command.ExecuteReader()
GridView1.DeleteRow(GridView1.FocusedRowHandle)
Take a look at the Posting Data to a Connected Database help-article:
The GridView.DeleteRow method removes a row from a grid's View and also deletes the object which represents this row in the GridControl's data source, but not from a database. To accomplish your task, you need to post changes to the database manually, for example using corresponding the methods of a Data Adapter object or EF-context.
GridView1.what?
To get row objects that correspond to specific row handles, use the ColumnView.GetRow or ColumnView.GetDataRow method.
In specific cases, you may need to obtain indexes of rows in the bound data source that correspond to specific row handles in Views. To do this, use the ColumnView.GetDataSourceRowIndex method.