I have a dataset with a datatable with Columns.
I fill dataset with this code in Winforms
myAdapter = New SqlDataAdapter("Select * from users", strSqlConn)
myAdapter.Fill(dsDataset, "Users")
dcPk(0) = dsDataset.Tables("Users").Columns("FirstName")
dcPk(1) = dsDataset.Tables("Users").Columns("LastName")
dsDataset.Tables("Users").PrimaryKey = dcPk
Is it anyway to check if any datatable.Columns is added vb.net? Later in code For example "amount" is added
dsDataset.Tables("Users").Columns.Add("amount", System.Type.GetType("System.Int32"))
What I really want - I have alot of datasets and I want to see if it any real changes in them (not added columns whois not part of the database) if not, dont save to database.
When I use GetChanges it says I have changes if I have added columns, but the added columns should be excluded.
Now I have hardcoded the added columns to exclude them in the check, it works but thats not a good way to maintain. Another way is to make a copy of all datasets and compare them, in the copy there is no added columns. But Im not sure about performance when its alot of datasets...
Like in rows
If row.RowState = DataRowState.Added Then
'Do something
end if
You should be able to use the GetChanges() method of the DataTable object, like so...
dim t as DataTable = MyDataTable.GetChanges()
If t IsNot Nothing then
' There were changes to the table
Else
' There were no changes to the table
End If
Please be sure to read the documentation page that I linked to be sure that it meets your requirements.
Related
I'm trying to delete the rows which the user selects in a datagridview using SQL Server.
I have a datagridview that loads the contents of the database, in this case Username and Password.
Keep in mind that each username is unique in the database and so I should be able to delete each row using the unique username.
The SQL I currently have is DELETE FROM 'Users&Passwords' WHERE 'Username' = ? I'm not sure if this is entirely correct, however whenever I click QueryBuilder it seems to accept it.
The code I have to try and do this is as follows:
Private Sub btn_remove_Click(sender As Object, e As EventArgs) Handles btn_remove.Click
For Each row As DataGridViewRow In DataGridView1.SelectedRows
Dim usernametodelete As String = DataGridView1.SelectedRows(0).Cells(0).Value.ToString
'TextBox1.Text += usernametodelete
Me.Users_PasswordsTableAdapter.DeleteUser(usernametodelete)
Me.Users_PasswordsTableAdapter.Fill(Me.ManageUsersDataSet._Users_Passwords)
Next
End Sub
I would like that when the user clicks the Remove User(s) button the selected rows from the datagridview remove the rows from the database. Any help would be greatly appreciated.
You're getting slightly more involved than you need to. The set of steps you'd ideally take would be:
0) rename your table so it doesn't have an & character in it - it's just asking for trouble
1) Add your table to your dataset with something like this process: right click the design surface, new tableadapter, configure the connection string, set the query as SELECT * FROM Users WHERE Username LIKE #username, ensure other things are set, like whether you want generate dbdirect methods, and whether you want the dataset to refresh new values
2) In your data sources window (might not be showing by default, find it in on of visual studio's menus) drag and drop the Users node from the data soruces window, out onto the form. This will create a datagridview bound to the typed datatable, and also create a dataset, tableadapter, tableadaptermanager (not strictly needed; can delete), a bindingnavigator tool strip (again not strictly needed but has a handy pre-wired Save button on it) and a bindingsource. It will also pre-fill some code into the form_load event handler to fill the datatable
3) That's it - your form has a grid, bound to a datatable. That grid is capable of deleting rows - click the row header and press the delete button on the keyboard, row disappears. Click the save icon in the toolstrip, and the change is persisted to the database. The only thing you have to do is get data into the table in the first place. I gave a SQL that allows you to choose some usernames to load, but you can easily make it load the whole lot by changing the line of code in Form_Load to:
yourTableAdapterName.Fill(yourDatasetname.YourDatatableName, "%")
Passing a percent as the name is like a * wildcard in DOS. LIKE % will select all records. You can also, of course, leave the default provision (it will reference a textbox on the toolstrip) and instead run the program, put a % in the textbox on the toolstrip and click Fill. Or you can put JOHNSMITH, or JOHN% in th textbox and fill, to load that user/those users respectively
Hopefully you already did 1 and 2..
A bit of a background story on how all this stuff works:
DataTables are client side representations of tables in the database. It isn't intended that they contain all the data in the database, only a portion of this that you want to work with. When you load a row from the DB you can edit it, delete it (mark as deleted) and when you call tableAdapter.Update(yourtable) th changes you made are persisted to the DB. Note that even though it's called Update, the method will save new rows (by doing an INSERT), deleted rows (SQL DELETE) and make updates (SQL UPDATE). If your datatable has 4 rows laodd from the DB, and you then add 2 new rows, make changes to 3 of the loaded rows and delete the 4th row, then calling tableadapter.Update will save all these changes to the DB. You aren't required to pick through your datatable, calling tableadapter.insert/update/delete accordingly, to manually persist these changes. The flow of using a tableadapter is thus:
tableAdapter.Fill(datatable, maybe,parameters,to,control,the,fill,here)
'work with the datatable here, change, insert, delete. Use loops/code, use the UI, etc
tableAdapter.Update(datatable) 'save changes
I suggest putting an id column in your datagridview and just hide it so that you can easily delete the record you want to remove easily without conflict, because if you will use a username, what if theres a duplicate username exist.
Private Sub BTNDELETE_Click(sender As Object, e As EventArgs) Handles BTNDELETE.Click
Public result As Integer = 0
Public cmd As New MySqlCommand
strcon.Open() 'your connection string here
With cmd
.Connection = strcon 'your connection string
.CommandText = "DELETE FROM `users` WHERE `id` = '" & DTGLIST.CurrentRow.Cells(0).Value.ToString() & "';"
result = cmd.ExecuteNonQuery
If result > 0 Then
MsgBox("Successfully Removed.", MsgBoxStyle.Information, "Info")
DTGLIST.Rows.Remove(DTGLIST.SelectedRows(0))
End If
End With
strcon.Close() 'close the connection string
End Sub
Managed to figure out why my delete query wasn't working a few days ago. It was due to my SQL not being correct. This worked for me DELETE FROM [Users&Passwords] WHERE (Username = ?).
Also having the line Me.Users_PasswordsTableAdapter.DeleteUser(usernametodelete) in my code made it work.
I seem to be pulling my hair out over something that seems pretty straight forward in my eyes. I cannot get a datagridview control to update correctly after altering a dataset.
I initially populate a datagridview from a dataset and auto generate the columns no problem. However, if I regenerate my dataset with new data, the datagridview will display the new data correctly, but won't remove the old column headers.
For example, I have a query that gives me Store Name and Manager and auto populates my datagridview. Then if I change my query to just give me Store Name and Supervisor, it gives me Store Name, Manager (with blank column) and Supervisor.
I have tried datagridview.refresh() and datagridview.update() but nothing seems to work.
Here is my code:
MySQLConn.Open()
Dim ExQry As New MySqlCommand(QryStr, MySQLConn)
ExQry.CommandType = CommandType.Text
Dim da As New MySqlDataAdapter(ExQry)
dasCustomQryData.Clear() 'my dataset is called dasCustomQryData
da.Fill(dasCustomQryData, "QryData")
da.Update(dasCustomQryData, "QryData")
With dgvCustomQuery
.DataSource = Nothing
.Dock = DockStyle.Fill
.AutoGenerateColumns = True
.DataSource = dasCustomQryData
.DataMember = "QryData"
.Refresh()
.Visible = True
End With
MySQLConn.Close()
da.Dispose()
dasCustomQryData.Dispose()
So, when I want to update my datagridview, I plugin a new QryStr to the above code and it rebuilds my dataset. The dataset is getting updated, because the datagridview contains the correct data, however, my problem is that the datagridview isn't clearing the old columns that aren't populated anymore.
All help appreciated. Thanks
I would recommend you create a connection and a dataset straight from VB and the in the dataset it shows the tables. At the bottom of the tables is a standard query but u can create your own...with variables as parameters and then you can call the query through the table adapter and assign this straight to the datagridview.
That always seems to work for my programs. What sort of database are u using? Might be obvious but just to make sure, the datagridview is not bound right? Sample from one of my projects dgData.DataSource = TblEventsTableAdapter.ViewEvent(cmbEvents.SelectedItem.ToString) where dgdata is obviously datagridview. ViewEvent is a custom query created in the dataset and takes in 1argument. Hope this is of use to you
Ok, after a bit of troubleshooting and playing around with code, I found that the simple solution to this was that the datatable itself was not releasing the column headers. So even though the datagridview and the dataset was getting cleared, the datatable was still populated.
The following command solved my issue:
dt.Columns.Clear()
For the life of me, I just cannot seem to get this to work. Here is the situation: I am trying to add the already existing customer custom field (already had a definition, but no value) to an estimate that I am currently creating via QBSDK 12. So far, I can add the estimate, the custom fields to the line items, but not the custom fields belonging to the customer in the estimate header area (reserved for customer information).
Here is my attempted code for the header (doesn't work):
If Not (DE.sconProof(x) Is Nothing) Or Not (DE.sconProof(x) = "") Then
Dim DataExtModRq As IDataExtMod
DataExtModRq = requestMsgSet.AppendDataExtModRq
' DataExtModRq.ORListTxn.TxnDataExt.TxnID.SetValue(sEstID)
DataExtModRq.OwnerID.SetValue("0")
DataExtModRq.DataExtName.SetValue("Proof Required")
DataExtModRq.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetEstimate)
DataExtModRq.ORListTxn.ListDataExt.ListObjRef.FullName.SetValue(DE.sconCompany(x))
DataExtModRq.DataExtValue.SetValue(DE.sconProof(x))
End If
Here is my working code for line items within the estimate (Does work):
If Not DE.sitemDateNeeded(i) = "" Then
Dim DataExt53 As IDataExt
DataExt53 = EstimateLineAdder.EstimateLineAdd.DataExtList.Append()
'Set field value for OwnerID
DataExt53.OwnerID.SetValue("0")
DataExt53.DataExtName.SetValue("In Hands By")
'Set field value for DataExtValue
DataExt53.DataExtValue.SetValue(DE.sitemDateNeeded(i))
End If
If Not DE.sitemSPC(i) = "" Then
Dim DataExt54 As IDataExt
DataExt54 = EstimateLineAdder.EstimateLineAdd.DataExtList.Append
DataExt54.DataExtName.SetValue("SPC")
DataExt54.DataExtValue.SetValue(DE.sitemSPC(i))
End If
The error message say's I am missing the TxnID but I am not modifying the estimate, I am creating a new one. I have tried the "IDataExt" as well but that doesn't work any better. If I need to save the newly created estimate, and then go back and add the TxnID, that would be really weird, and I'm not sure of a simple way to do that. I should be able to add data to the custom field in the header portion of the estimate without going through so much "hoopla". Please help me if you know the answer.
I figured it out...
If Not (DE.sconProof(x) Is Nothing) Or Not (DE.sconProof(x) = "") Then
Dim DataExtModRq As IDataExtMod
DataExtModRq = requestMsgSet.AppendDataExtModRq
DataExtModRq.DataExtName.SetValue("Proof Required")
DataExtModRq.DataExtValue.SetValue(DE.sconProof(x))
DataExtModRq.OwnerID.SetValue("0")
'DataExtModRq.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetEstimate)
DataExtModRq.ORListTxn.ListDataExt.ListDataExtType.SetValue(ENListDataExtType.ldetCustomer)
DataExtModRq.ORListTxn.ListDataExt.ListObjRef.FullName.SetValue(DE.sconCompany(x))
'DataExtModRq.ORListTxn.TxnDataExt.TxnID.SetValue(sTxnID)
End If
I know my title is a little strange. Let me explain. I am trying to "merge" two databases, one we house locally and one that is at another facility with the hopes of avoiding our admin group having to duplicate entry through separate forms. I have the source for a webservice that connects to the offsite database and I can enter data. What I am trying to do is expand that source by adding in our own database and copying our data to theirs. Hope this makes sense.
Anyway,
So both the local and offsite forms have datagridviews attached to them. I can currently copy the contents of the first row to their form for entry, but I am getting errors when it attempts to go to the second row. Here is my code:
Dim i As Integer
For i = 0 To VRMAdDataGridView.Rows.Count - 1
'For Each row As DataGridViewRow In VRMAdDataGridView.Rows
'myrow = VRMAdDataGridView.CurrentRow.Index
frmcall.dgvRMAItems.Rows(i).Cells("cItemID").Value = Me.VRMAdDataGridView.Rows(i).Cells("DataGridViewTextBoxColumn5").Value
frmcall.dgvRMAItems.Rows(i).Cells("cExpectedSerialNumber").Value = Me.VRMAdDataGridView.Rows(i).Cells("DataGridViewTextBoxColumn2").Value
frmcall.dgvRMAItems.Rows(i).Cells("cNotes").Value = Me.VRMAdDataGridView.Rows(i).Cells("DataGridViewTextBoxColumn3").Value
'Format Type codes from FW to match Utica
Select Case Me.VRMAdDataGridView.Rows(i).Cells("DataGridViewTextBoxColumn6").Value
Case "Repair"
frmcall.dgvRMAItems.Rows(i).Cells("cRequestedAction").Value = "Repair"
Case "RTS"
frmcall.dgvRMAItems.Rows(i).Cells("cRequestedAction").Value = "Rtn/Stock"
Case "Repair !!RUSH!!"
frmcall.dgvRMAItems.Rows(i).Cells("cRequestedAction").Value = "Rush Repair"
End Select
' myrowval = row.Cells("DataGridViewTextBoxColumn5").Value
' MsgBox(myrowval, MsgBoxStyle.Information, "Prod_Code")
'Do Something
Next
When I try to run the code I receive the following error:
{"Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"}
You should manipulate the underlying datasources, not UI elements (DataGridViews in this case). For example, your DataSource is a DataTable. Then just use Clone method to get a copy. Then set a DataSource of that other DataGridView. If you need something more than a copy, it's definitely going to be more simple to work with a series of DataRow objects.
I have a basic question about using a database with Visual Basic.
I'm using a OleDb connection. I have dragged and dropped editboxes
from the DataDource view. This automatically places the table navigation-
bar on the form. When I run it this works fine.
However I want to be able to search within the table, with an SQL statement.
How can I connect the results from the SQL query to the navigation bar,such that
the editboxes automatically take the values of the record without having to
assign every textbox manually?
Thank you very much.
This little snippet seems to work, although you have to specify the Sort columns for your table, and if you want to sort by multiple fields then on the Find call you pass an array of Object() types that correspond to the values you are searching for (in the order of the Sort values. Let me know if it works for you or if you have any other questions about it.
'**** Sample table structure for Database1Dataset.Table1
' Col1 Col2 Col3
'(row) "Row1.Col1" "Row1.Col2" "Row1.Col3"
'(row) "Row2.Col1" "Row2.Col2" "Row2.Col3"
'(row) "Row3.Col1" "Row3.Col2" "Row3.Col3"
Dim dv As DataView = Me.Database1DataSet.DefaultViewManager.CreateDataView(Database1DataSet.Table1)
dv.Sort = "Col1"
Me.Table1BindingNavigator.BindingSource.Position = dv.Find("Row2.Col1")
Here is an example with multiple sort columns
Dim dv As DataView = Me.Database1DataSet1.DefaultViewManager.CreateDataView(Database1DataSet1.Table1)
Dim FindValues(1) As Object
dv.Sort = "Col1,Col3"
FindValues(0) = "Row2.Col1"
FindValues(1) = "Row2.Col3"
Me.Table1BindingNavigator.BindingSource.Position = dv.Find(FindValues)