When I start a fresh debug of my windows form app I can add multiple records into the "klant" table with no problem. They are all saved inside the coupled SQL database. When I Quit debugging and restart the app and I add 1 new record all previous records are deleted and that one new record is now the first record inside the table.. If I add multiple records the previous records are also gone
the code is simple:
Public Class DALKlant
Dim dc As New DumbbellDataContext
Dim klant As New klant
Public Sub AddKlant(ByVal klant As klant)
dc.klants.InsertOnSubmit(klant)
dc.SubmitChanges()
End Sub
End Class
Edit: at first I wasn't able to save any data at all, I had to redirect the connection string towards the mdf. in the bin/debug/app_data folder. Don't know if this can be related with the problem.
Related
Im using vb.net windows forms, VS 2019, .net framework 4.7.2 and mysql.
I tried datagridview in a form to display data from my database and its working perfectly fine.
But,
when i tried to use the same procedure, displaying data from the same database using datagridview in a child form (which i call via parent form that docks the child form over a region in parent form), it is not displaying any data, while the query works perfectly fine, its updating the data in database, but the data isn't displaying in this parent-child case.
Tho, the same code works perfectly fine and displays data if its used in a separate form.
I don't know what is the problem actually.
I had to attach more than one picture to explain clearly so i uploaded them and the link is given as:
https://imgur.com/a/6xka1B4
But, i have merged all the snips of the code from different forms as well:
1 The sub-class Custom_LoadDataGrid is called here and working correctly and displaying data in the gridview
DB.Custom_LoadDataGrid("SELECT item_name as 'NAME', item_price as 'PRICE', quantity as 'QUANTITY', Amount as 'AMOUNT' FROM transaction WHERE client_name ='" + Label11.Text.ToString + "'")
DB.myConnection.Close()
2 The sub Custom_LoadDataGrid which was called above
Public Sub Custom_LoadDataGrid(ByVal search As String)
Try
connString = "server=127.0.0.1;Port=3306;Database=smartcart;Uid=root;Pwd="
myConnection.ConnectionString = connString
myConnection.Open()
sql = search.ToString
DataAdapter = New MySqlDataAdapter(sql, myConnection)
Datacmd = New MySqlCommand(sql, myConnection)
DataAdapter.Fill(DataSet, DbName)
MaxRows = DataSet.Tables(DbName).Rows.Count
Dim dt1 As New DataTable
DataSet.Tables.Add(dt1)
DataAdapter.Fill(dt1)
Portal.Guna2DataGridView1.DataSource = dt1.DefaultView
ReleaseDb()
Catch ex As Exception
MsgBox("Something went wrong")
End Try
End Sub
3 i made this sub-class to call child forms and dock in the region somewhere in the parent forms
Private Sub OpenChildForm(childForm As Form)
'Open only form'
If currentChildForm IsNot Nothing Then
currentChildForm.Close()
End If
currentChildForm = childForm
'end'
childForm.TopLevel = False
childForm.FormBorderStyle = FormBorderStyle.None
childForm.Dock = DockStyle.Fill
Controls_panel.Controls.Add(childForm)
Controls_panel.Tag = childForm
childForm.BringToFront()
childForm.Show()
End Sub
4 here the child form is called
Private Sub Stock_manag_button_Click(sender As Object, e As EventArgs) Handles Stock_manag_button.Click
Sub_menu_panel.Hide()
ActivateButton(sender)
OpenChildForm(New Stock_management)
End Sub
5 This sub-class Custom_Load_DataGrid is called here but is not displaying data in gridview
DB.Custom_Load_DataGrid("SELECT * FROM addition_stock ")
DB.myConnection.Close()
'6 the sub-class Custom_Load_DataGrid is exactly same as Custom_LoadDataGrid (but obviously with different variables and relavent form name)
but this is not displaying data in gridview just in this this case of parent-child forms tho this one works fine too when used for seperate
forms.
Public Sub Custom_Load_DataGrid(ByVal search As String)
Try
connString = "server=127.0.0.1;Port=3306;Database=smartcart;Uid=root;Pwd="
myConnection.ConnectionString = connString
myConnection.Open()
sql = search.ToString
DataAdapter = New MySqlDataAdapter(sql, myConnection)
Datacmd = New MySqlCommand(sql, myConnection)
DataAdapter.Fill(DataSet, DbName)
MaxRows = DataSet.Tables(DbName).Rows.Count
MsgBox(MaxRows.ToString)
Dim dt2 As New DataTable
DataSet.Tables.Add(dt2)
DataAdapter.Fill(dt2)
Stock_addition.Guna2DataGridView1.DataSource = dt2.DefaultView
ReleaseDb()
Catch ex As Exception
MsgBox("Something went wrong")
End Try
End Sub
Can I get you to do this, in a new project, as a mini tutorial to make your life easier:
make a new project
Add a Form
Add a DataSet
Open the DataSet, right click in the surface and add a tableadapter
create a connection string to store in the settings: Pick mysql connector (note for this to work you need mysql connector AND ALSO mysql for visual studio https://dev.mysql.com/downloads/windows/visualstudio/ ) and fill in the details to create a database connection string make sure the test connection succeeds
proceed through the wizard choosing "query that returns rows", "by sql", enter a query of SELECT * FROM addition_stock WHERE ID = #id
write names of FillByID, and GetDataByID
finish
You'll see something that looks like a database table appear, with a thing called addition_stockTableAdapter underneath it
Right click the tableadapter, choose add .. query
add another query that is more relevant to how you will search this table, like maybe SELECT * FROM addition_stock WHERE stock_code = #stockCode
call it FillByStockCode/GetDataByStockCode
always give relevant names to your fill/get data methods
Always make the first query that creates the datatable/tableadapter pair a "select where id =" - it makes things easier later on. Add as many additional queries as you will need
Do the same thing again (Add a tableadapter) this time with a table that is either a parent or a child of addition_stock - it doesn't matter which, I'm just trying to demonstrate something here. Make sure you use a table that has a foreign key in the database, to addition_stock
Once you add your other datatable/tableadapter pair that is related to addition_stock you will see a line connecting the two datatables
Right click this line and choose "show relation labels" to display the name of the relation - it comes from the foreign key in the database
Now we are going to add a convenience method to load child data based on the parent id
Right click your child tableadapter and choose Add Query
add a query of SELECT * FROM tablenamehere WHERE parentidcolumnnamehere = #parentid and call it a suitable FillByXxx - obviously Replace the table name, column name and xxx with real values
save your DataSet and switch to the forms designer
show the Data Sources window (view menu.. other windows)
expand all the nodes of your DataSet - you'll see a parent table and two child tables, one underneath the parent, one not
drag the parent table out of datasources and onto the form - a datagridview with columns will appear, as will a tableadapter, bindingnavigator, DataSet and a bindingsource in the tray at the bottom. The nav has a textbox you can write an id into and a button to press. The datagridview columns are set up appropriately and the grid is bound to the bindingsource. The bindingsource is bound to the DataSet parent table.
run the app, enter an ID in the textbox, click fill, edit the name of something, click save, go use mysql workbench to look in the db. Super; you can download, edit and save db data and you haven't written a single line of code; you're just using the thousands of lines of code visual studio has written for you.
stop the app, go back to the forms designer
drag the child table that is underneath the parent table onto the form. More items appear - a datagridview bound to another bindingsource, another navigator etc. You can delete this second navigator- we won't use it
take a look at the bindingsource of the child table - note that it is NOT bound directly to the DataSet but instead it is bound to the other bindingsource, with a DataMember property that is set to the name of the relation line between the two tables
switch to code view and look at the code of the Fill toolstripmenu that fills the parent record by the id/whatever. If there is any redundant code from the child bindingnavigator, remove it (or comment it out: it could be slightly useful for the next step
under the line of code that fills the parent datatable by id put the following code:
childTableAdapter.ClearBeforeFill = False
yourDatasetName.ChildTableName.Clear()
For Each parentRow in yourDataSetName.YourParentTableName
childTableAdapter.FillByParentId(yourDataSetName.ChildTableName, parentRow.Id)
Next
Run the app again, enter the parent id, click fill. The parent data and the related child data loads. Great, but the real magic happens when we load multiple parent rows. Go back to code and swap the FillById on the parent tableadapter for the other query you write (if you didn't do one, go back to DataSet, Add a query to the parent table adapter that loads multiple rows, like select * from person where lastname = #lastname so we can enter a last name like smith, of which there are many) so now your code looks like this in the fill:
parentTableAdapter.FillBySonethingThatGetsMultipleRows(yourDataSetName.ParentTableName, fillByTextboxName.Text)
childTableAdapter.ClearBeforeFill = False
yourDatasetName.ChildTableName.Clear()
For Each parentRow in yourDataSetName.YourParentTableName
childTableAdapter.FillByParentId(yourDataSetName.ChildTableName, parentRow.Id)
Next
You'll note that you get multiple parent rows, you load multiple sets of child rows in the loop, but when you run the app and you choose a different parent in the parent grid the child grid automatically filters to show only the children of the currently selected parent
I have tried making a dataset using the dataset tool to link it on the design side however that hasn't worked as it keeps disappearing and this is the other way it does not display any values on the datagrid view i am unsure why and i am fairly new to this side of vb so if you could explain it as well that would be great. Thanks in advance.
Imports MySql.Data.MySqlClient
Public Class Search
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
If TextBox1.Text = "" Then 'this acts as a simple presence check on the textbox
Else
Dim val = "name"
If RadioButton1.Checked = True Then 'This changes the type of search i do as it filters which column the query looks in
val = "type"
End If
Await getDataSet(TextBox1.Text) ' waits for infomation to be retrieved
End If
Catch ex As System.Exception
System.Windows.Forms.MessageBox.Show(ex.Message) 'Catches any errors
End Try
End Sub
Async Function getDataSet(partname As String) As Task(Of DataSet) 'This retrieves the values that matches the users input
Return Await Task.Factory.StartNew(
Function()
Dim connectionString = "server=localhost; userid=root; password=; database=partstest1; CharSet=utf8;" 'These are the login details for the database in the form of a connection string
Dim commandText = "SELECT ID, Benchpoint, Name, Type, BrandID FROM `parts` WHERE `name` Like '%" & TextBox1.Text & "%';"
Using connDB = New MySqlConnection(connectionString), objCmd = New MySqlCommand(), objAdpt = New MySqlDataAdapter()
connDB.Open()
objCmd.Connection = connDB
objCmd.CommandText = commandText
objCmd.CommandType = CommandType.Text 'These lines specify the command i am using and execute it
objAdpt.SelectCommand = objCmd
Dim objDs = New DataSet()
objAdpt.Fill(objDs) 'Puts all of the values into a dataset
PartsDataGridView.DataSource = objDs.Tables(0) 'This shows the datasource and displays it
Console.WriteLine(objDs)
Return objDs
End Using
End Function)
End Function
End Class
Install MySQL/connector/etc
Install MySQL for Visual Studio (needed to get it to show as a datasource in VS) - https://dev.mysql.com/downloads/windows/visualstudio/
Add a new dataset to your project
Double click the dataset, right click the surface of it, choose Add >> TableAdapter
Choose existing connection or New Connection if you have no existing. Choose MySQL Database (install MySQL for Visual Studio from step 2 if this is absent)
Enter server details, choose to save the password, back in the wizard choose Yes, include sensitive.. and click Next, choose Yes, save the connection string, click Next, choose Use SQL Statements, Next, enter a suitable query that selects based on the primary key such as SELECT * FROM yourtable WHERE id = #id, Next, call the methods FillById and GetDataById to distinct them from other queries you may add later like FillByCity or GetDataByStatus. At the end of this wizard you should have a datatable and tableadapter that looks like your database table:
Switch to the form designer, and also ensure that the Data Sources window is visible (click View Menu >> Other Windows >> *Data Sources**), expand all the nodes in the Data Sources panel
Drag the node representing your table (mine is called person) out of the datasources window and drop it on the form. Several things will appear:
a datagridview already bound to the dataset's datatable showing person data,
a toolstrip with a textbox for inputting the ID (remember you made a query that takes a parameter),
another toolstrip with navigators and a save button),
a dataset (needed to store the data),
a bindingsource (acts as a link between the dataset's datatable and the grid, knows what current record is showing, allows sorting and filtering),
a tableadapter (an enhanced data adapter that will pull data from the db into the dataset and send back any changes),
a tableadapter manager (a device that knows what order to run updates in for hierarchical data)
Also, as a demonstration of how it works, drag all the nodes UNDERNEATH person onto the form also - you can see they have different icons. They will re-use most of the components on the form but you'll get textboxes, datetimepickers, checkboxes etc that are bound to the bindingsource and will hence show the current item from the underlying list (the datagridview shows them all, with an indicator of which row is current)
Run the project, type an ID into the textbox, hit **FillById*, write some new info into another row at the bottom - it will commit to the underlying dataset/datatable when you change row in the DGV, note that flicking back and forth between the rows in the DGV causes the textboxes to change as the notion of Current row is updated (navigating the grid, or clicking the arrows in the navigator changes the bindingsource .Current property, and all controls bind through the bindingsource
hit save - now go look in your db in MySQL Workbench - the new record is there. You've made a full databound UI, and not written a line of code - all the code is there in the FormX.vb if you want to see it - written for you by the designer. Take a look
Note that it still says -4 (in my UI) for the temp id; the program didn't download the new ID that was assigned by the DB. To make it do this, youre supposed to be able to go back to your dataset, right click the tableadapter, click Advanced Options, and tick on Refresh the datatable - this will cause the adapter to update any local IDs after it saves the row. IDs can cascade update if they are part of a datarelation between two datetables. In MySQL this doesn't work (I'm reporting a bug to them now), but you can make it work by manually editing the XML file representing the dataset (right click the DataSet in solution explorer, choose Open With.. Choose XML Editor, locate the insert statement eg:
INSERT INTO `person` (`Name`, `Birthdate`, `Salary`) VALUES (#p1, #p2, #p3)
Add another statement after it so it looks like:
INSERT INTO `person` (`Name`, `Birthdate`, `Salary`) VALUES (#p1, #p2, #p3)
;SELECT `Id`, `Name`, `Birthdate`, `Salary` FROM `person` WHERE `Id` = last_insert_id()
Now, saving the table will cause the UI to refresh with the ID values calculated by the auto increment in the DB
I'm trying to design a simple wildlife tracking DB, so that when myself or my colleagues spot an animal we can enter its ear tag number via a form. That will either bring us up a list of previous dates/locations that animal was observed, or if it's not in the DB, allow us to enter the new animal and location.
I have two main data tables:
dt_Animal - which stores the ear tag info, species, and other information about that unique animal
dt_Sightings - stores info on when/where animals been seen (linked to dt_Animal in a one-to-many relationship, of course)
What I want is that when you open up the form, you get a box (text or combo) to enter the animal's ear tag ID.
If the ID already exists in the DB, it brings up all the info on that animal and its previous sightings - with the option to fill out any missing info and (of course) to add a new sighting - and it WILL NOT add a new record to dt_Animal - just to dt_Sightings
If the ID doesn't exist in the DB, it creates a new record in dt_Animal and allows you to enter any/all of the other information
Where I'm running into problems is that I don't want duplicate records in dt_Animal - each animal is unique.
So far, I've gotten it so that if the eartagID value you've entered is already present in dt_Animal, instead of just popping up a warning, the form will bring up the associated data in the 'Sightings' subform, so you can see where the animal has been previously as well as add your new sighting.
Any help would be appreciated! I had been getting some help at another forum until the person helping me was banned for a fracas on another thread...!
http://www.access-programmers.co.uk/forums/showthread.php?p=1249087
Thanks!
If you haven't tried it already, I would suggest using a Form for Animals that uses standard text boxes, combo boxes, etc., to display/edit the animals' details and uses a linked Subform control to display/edit their sightings all at once, like this:
The main form is bound to [dt_Animal], so you don't run the risk of creating duplicates in that table if [eartagID] is the Primary Key (which it should be). The "Sightings" subform is bound to [dt_Sightings] and linked to [dt_Animal] by [eartagID], so
it only shows the Sightings for the current Animal
if you add a new Sighting it will automatically link that Sighting to the current Animal (i.e., automatically insert the correct [dt_Sightings].[eartagID]).
Edit
To make searching/adding animals more "seamless", one approach would be to add a text box txtAddSearch and a command button cmdAddSearch to the form header with the following code behind the form:
Option Compare Database
Option Explicit
Private Sub cmdAddSearch_Click()
Dim rst As DAO.Recordset
If Not IsNull(Me.txtAddSearch.Value) Then
Set rst = Me.RecordsetClone
rst.FindFirst "eartagID=" & Me.txtAddSearch.Value
If rst.NoMatch Then
DoCmd.GoToRecord acDataForm, Me.Name, acNewRec
Me.eartagID.SetFocus
Me.eartagID.Text = Me.txtAddSearch.Value
Me.species.SetFocus
Else
Me.Bookmark = rst.Bookmark
End If
Set rst = Nothing
End If
End Sub
Private Sub Form_Load()
Me.cmdAddSearch.Default = True
Me.txtAddSearch.SetFocus
End Sub
When the form first loads you are looking at the first data record, but txtAddSearch has the focus:
You type in an EarTagID and hit [Enter]. If the record already exists then you are taken to it...
...and if the EarTagID doesn't already exist you are taken to a new record (with that EarTagID already filled in) so you can add the details:
I am about to write a ews-application to connect exchange with another calendar programm. What occured to me, how do I get to know, which appointments get deleted on exchange? Is there a way to tell? I couldn't find it in the API and documentation.
Thanks in advance.
Depending on how a user deletes an appointment (or any item), different things are done:
Soft-Delete: The item is moved to the recycle bin of the mailbox.
Hard-Delete: The item is instantly removed.
You have multiple ways to get information about deleted items:
Query the folder using a FindItems call and select ItemTraversal.Associated in the Traversal property of the ItemView. Note: This requires Exchange 2010.
Use the SyncFolderItems at one time and store the synchronization cookie somewhere. Later, execute the SyncFolderItems again using the previously stored cookie. Exchange will now give you a detailed list of changes which happened to the folder.
Query the Recycle bin for appointments. They will most likely have come from the default calendar of the user.
I wrote a service that syncs EWS Calendar Appointments to a Sql Table.
For deletion after Inserting/Updating changes if there is a row in the database and not in EWS I will delete it, as this means it was deleted in Exchange. I use GUIDs to track the appointment in database and exchange. Exchange web services: why is ItemId not constant? [continued]
Performance is decent with just couple dozen appointments, I will try it on much larger dataset.
Dim appointmentGuid As New List(Of String)
For Each appointment In appointments 'appointments is IEnumerable(Of Appointment) from EWS
Dim guid As String = GetGuidForAppointment(appointment)
If String.IsNullOrEmpty(guid) Then
SetGuidForAppointment(appointment)
guid = GetGuidForAppointment(appointment)
End If
appointmentGuid.Add(guid)
'Upsert rows
...
Next
'Delete orphaned rows
Using sqlConnection As New SqlConnection(ConnectionString)
Dim deleteScript As New StringBuilder()
Using sqlCmd As New SqlCommand("SELECT ID FROM Appointments", sqlConnection)
Using sqlDataReader As SqlDataReader = sqlCmd.ExecuteReader()
sqlConnection.Open()
While sqlDataReader.Read()
Dim guid As String = sqlDataReader.GetString(0)
If Not appointmentGuid.Contains(guid) Then
deleteScript.AppendFormat("DELETE FROM Appointments WHERE ID = '{0}'; ", guid)
End If
End While
End Using
End Using
If deleteScript.Length > 0 Then
Using sqlCmd As New SqlCommand(deleteScript.ToString(), sqlConnection)
sqlCmd.ExecuteNonQuery()
End Using
End If
End Using
I have a very difficult task, that I think exceeds my level of knowledge of databases. I am only learning it for a week, so I require help.
I currently have an old database that has tables for requests and customers. This information is currently displayed in ASP.NET
What I was required to do, was to connect a new database for users into this system, while keeping the tables for the requests in the old database. Thus it is using 2 databases. I have set it up so, when a user creates a new request, in the request tables it saves it with his userID from the new database, but when the table is being displayed, it uses this new userID to find the user information from the old customers table. Thus I ended up with this:
Sub BindDataGrid()
cmdoledb = New SqlCommand("SELECT r.customerid, r.RequestID, R.RequestDate, R.RequestDescription, a.AssignedTo, r.Urgency, r.ExCompletionDate from tbl_requests r, tbl_assignedto a where r.statusid = 1 and r.assignedtoid= a.assignedtoid ", objConn)
objConn.Open()
Dim rdr As SqlDataReader
Dim myItem As ListItem = New ListItem()
rdr = cmdoledb.ExecuteReader(0)
While rdr.Read()
myItem = New ListItem()
myItem.Value = rdr.GetInt32(0)
cmddb = New SqlCommand("SELECT SESFirstName + ' ' + SESLastName As fullname from SESLogin where SESLoginID = #customerID", objConnect)
cmddb.Parameters.AddWithValue("#customerID", myItem.Value)
objConnect.Open()
Dim anotherAdapter As New SqlDataAdapter(cmddb)
Dim dss As New DataSet
anotherAdapter.Fill(dss)
dgrdUsers.DataSource = dss
objConnect.Close()
End While
Dim myAdapter As New SqlDataAdapter(cmdoledb)
Dim ds As New DataSet
myAdapter.Fill(ds)
dgrdUsers.DataSource = ds
dgrdUsers.DataBind()
objConn.Close()
End Sub
Currently it displays nothing, and gives out an error for myItem.Value = rdr.GetInt32(0) being a Null. I went through it step by step and it loads customerids normaly into the myItem.Value, but when they run out, it is supposed to exit, but keeps going, thus giving an error.
This code is very silly i know, but with my knowledge, this is what I was able to come up with. Thus I require your help and advice, to fix this issue I am having.
Well, the first thing I would do is combine your two databases into one (preferably using views as replacements for you existing tables), if indeed you are using two dbs (it's not clear from your code sample whether you really are using two dbs or simply additional tables).
You are executing you primary query twice, once for a data reader and once for a dataadapter.fill. You should do the fill first and then iterate over the resulting rows. The code sample is using a list item in oreder to contain a single integer, unless you are not showing all of your code, you should just use an integer variable.
I don't know if it fits in with what you are doing or not, but you only need one dataset with two tables to contain the data you are retrieving.