First of all I´m developing a database with autosuggest box. I´ve created a database with DB Browser and imported data. I was reading documentation in C# how connect database and retrieve data. The issue is show up an exception error:
enter image description here
I´ve connected the database in properties with content option. I paste the code:
Public NotInheritable Class METARTAF
Inherits Page
Dim dbpath As String = Path.Combine(ApplicationData.Current.LocalFolder.Path, "airportsdb.sqlite3")
Dim conn As SQLite.Net.SQLiteConnection = New SQLite.Net.SQLiteConnection(New WinRT.SQLitePlatformWinRT(), dbpath)
Dim airportinfo As List(Of String) = Nothing
Public Sub New()
' This call is required by the designer.
InitializeComponent()
End Sub
Private Sub AutoSuggestBox_TextChanged(sender As AutoSuggestBox, args As AutoSuggestBoxTextChangedEventArgs)
Dim datairport As New List(Of String)
Dim retrieve = conn.Table(Of flugzeuginfo)().ToList
If args.Reason = AutoSuggestionBoxTextChangeReason.UserInput Then
If sender.Text.Length > 1 Then
For Each item In retrieve
datairport.Add(item.IATA)
datairport.Add(item.ICAO)
datairport.Add(item.Location)
datairport.Add(item.Airport)
datairport.Add(item.Country)
Next
airportinfo = datairport.Where(Function(x) x.StartsWith(sender.Text)).ToList()
sender.ItemsSource = airportinfo
End If
Else
sender.ItemsSource = "No results..."
End If
End Sub
Private Sub AutoSuggestBox_SuggestionChosen(sender As AutoSuggestBox, args As AutoSuggestBoxSuggestionChosenEventArgs)
Dim selectedItem = args.SelectedItem.ToString()
sender.Text = selectedItem
End Sub
Private Sub AutoSuggestBox_QuerySubmitted(sender As AutoSuggestBox, args As AutoSuggestBoxQuerySubmittedEventArgs)
If args.ChosenSuggestion Is Nothing Then
stationidtxt.Text = args.ChosenSuggestion.ToString
End If
End Sub
Anyone could help about this?
Before you query or insert into a table, you should CREATE it. This tells SQLite what columns you have and suggests datatypes (on other rdbms's you get actual data type enforcement but SQLite does not do that). If this is your problem, you will want to spend some time with the SQLite documentation on data types and the ability to hook them into your application.
On the other hand, as you seem to be trying to retrieve data, this suggess one of two things is wrong. Either you care connecting to the wrong db (in which case SQLite will usually helpfully create an empty db for you!) or else you are specifying the wrong table.
Related
I am doing a small system using Ms. Access (the database has more than 10 tables ) connecting to visual studio. I made a public class for opening the connection to the database so I can use it in every form. Everything is working and I can get the data from the database But any inserting or deleting data in forms, the database in ms access not getting the update. I can see the new records in forms but nothing in the database.
Imports System.Data.OleDb
Public Class dbconnectClass1
'create db connection
Private DBcon As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=dental_clinic.accdb;")
'prepare db command
Private dbcmd As OleDbCommand
' db data
Public DBDA As OleDbDataAdapter
Public DBDT As DataTable
'query parameters
Public params As New List(Of OleDbParameter)
'query statics
Public recordcount As Integer
Public Exception As String
Public Sub ExecQuery(query As String)
'reset query status
recordcount = 0
Exception = ""
Try
'open connection
DBcon.Open()
'create db command
dbcmd = New OleDbCommand(query, DBcon)
'load params into dbcommand
params.ForEach(Sub(p) dbcmd.Parameters.Add(p))
'clear params list
params.Clear()
'excute command and fill dataset
DBDT = New DataTable
DBDA = New OleDbDataAdapter(dbcmd)
recordcount = DBDA.Fill(DBDT)
Catch ex As Exception
Exception = ex.Message
End Try
'close the database connection
If DBcon.State = ConnectionState.Open Then DBcon.Close()
End Sub
'include query and command parameters
Public Sub addparam(name As String, value As Object)
Dim newparam As New OleDbParameter(name, value)
params.Add(newparam)
End Sub
End Class
This my code inside the forms:
Public Class NewExpense
Private access As New dbconnectClass1
' a varuble having the appointment Id to connect between 2 forms
Private appointmentNo As Integer
Private Function NoError(Optional report As Boolean = False) As Boolean
If Not String.IsNullOrEmpty(access.Exception) Then
If report = True Then MsgBox(access.Exception)
Return False
Else
Return True
End If
End Function
Private Sub Savebuttum_Click(sender As Object, e As EventArgs) Handles
Savebuttum.Click
Dim oDate As DateTime = Convert.ToDateTime(DateTimePicker1.Value)
access.addparam("#expensenme", expensenmtXT.Text)
access.addparam("#expensedetail", ExpenseDetailTXT.Text)
access.addparam("#expenseamount", ExpenseAmountTXT.Text)
access.addparam("#expensedate", oDate)
access.addparam("#expensepaidTo", paidtoTXT.Text)
access.ExecQuery("INSERT INTO Expense (Expenses_name, expense_details,
expenses_amount, ExpenseDate_Paid, ExpensePaid_To) Values (#expensenme,
#expensedetail, #expenseamount, #expensedate, #expensepaidTo);")
'report on errors
If Not String.IsNullOrEmpty(access.Exception) Then
MsgBox(access.Exception) : Exit Sub
'success
access.DBDA.Update(access.DBDT)
MsgBox("Expense Has been Added Successfully")
End Sub
End Class
Hum, you have this:
params.ForEach(Sub(p) dbcmd.Parameters.Add(p))
Great, we add the parmaters - looks good to go!!!
then, next line CLEARS all the work above!!! (the parameters are removed!!!!)
'clear params list
params.Clear()
Next up? Many will build a connection object, then a reader, and then a adaptor. But you ONLY need a data adaptor if you going to update a data table. if you just going to execute a command, then you don't need the data table, and you don't need a adaptor FOR that table. Adaptor = ability to modify a existing datatable (or dataset).
You are MUCH better to use the command object.
Why?
Because the command object has a connection object (don't need a separate one)
Because the command object has a data reader for you (no need for a whole data adaptor to JUST fill a table. And remember, you don't need a whole data adaptor UNLESS you are going to send/update a data table back to the database.
And because the command object has the command text, then you don't even need a variable for that!!!
And because all objects are in "one object", then really all you need is something to handy get you the connection.
So, for your insert example, we really don't gain by having that object, do we?
Ok, so here is your insert code without using those extra objects:
so in the following, I declare ONE variable, - the sql command object.
And do the insert
And as FYI? Your save button is not a save - but a insert button - every time you hit it, you will insert a new row. Lets deal with that issue in a bit.
So, here is our code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using cmdSQL As New OleDbCommand("INSERT INTO Expense
(Expenses_name, expense_details,expenses_amount, ExpenseDate_Paid, ExpensePaid_To)
Values (#expensenme,#expensedetail, #expenseamount, #expensedate, #expensepaidTo)",
New OleDbConnection(My.Settings.TESTOLEDB))
With cmdSQL.Parameters
.Add("#expensenme", OleDbType.WChar).Value = expensenmtXT.Text
.Add("#expensedetail", OleDbType.WChar).Value = ExpenseDetailTXT.Text
.Add("#expenseamount", OleDbType.Currency).Value = ExpenseAmountTXT.Text
.Add("#expensedate", OleDbType.DBDate).Value = DateTimePicker1.Value
.Add("#expensepaidTo", OleDbType.WChar).Value = paidtoTXT.Text
End With
cmdSQL.Connection.Open()
cmdSQL.ExecuteNonQuery()
End Using
So things in above:
We have strong data typing and converstion.
Because of this, note how I did NOT have to create a separate date/time variable here.
Note the SAME for "money" or so called currency conversion - again strong data type by using parameters this way.
And is this a date only, or a date+ time value? If it is date, then
.Add("#expensedate", OleDbType.DBDate).Value = DateTimePicker1.Value
If it was/is a date + time, then this:
.Add("#expensedate", OleDbType.DBTimeStamp).Value = DateTimePicker1.Value
So, notice how all your object stuff REALLY did not help one bit, and in fact you did not really save code, and above actually had LESS variables defined to do the whole job.
Now, back to the insert issue/problem. (you save is doing a insert). But what about editing existing records?
So, I would suggest you work out the problem this way:
You create/get/have/assume a data row for the form.
The form takes the data row, fills the controls. You edit, and when you hit save, the data row is sent back to the datbase. So, once this works, then to add? Well, the add code will CREATE a new data row, save to database and THEN you send that new data row to the above eixsting form that can edit a data row, and can save a data row. So the form now is able to deal with both issues (adding vs editing existing). If the user dont' want the row, then you offer a delete button.
And REALLY nice is a data row means you don't deal with SQL, and don't deal with parmaters!!
So the code (desing pattern) I use is thus this:
dim da as oledbDataAdaptor
dim myTable as DataTable = MyRstEdit("SELECT * from tblHotels WHERE ID = " & lngID,da)
dim MyDataRow as DataRow = myTable.Rows(0)
' code to fill controls
txtHotelName.Text = MyDataRow("HotelName")
txtCity.Text = MyDataRow("City")
' etc. etc. etc.
Now to save? Well I put the values back into that DataRow like this:
MyDataRow("HotelName") = txtHotelName.Text
MyDataRow("City") = txtCity.Text
MyDateRow("BookingDate") = txtTimePick1.Value
da.Update(MyTable)
Notice how I don't have parameters, and even strong data type checking occurs for say the above Date/Time booking date column.
And the above is nice, since I don't have to deal with ANY parmaters to udpate a row of data.
The MyRstEdit routine looks like this and returns byREf a "da" (data adaptor).
Public Function MyrstEdit(strSQL As String, Optional strCon As String = "", Optional ByRef oReader As SqlDataAdapter = Nothing) As DataTable
' Myrstc.Rows(0)
' this also allows one to pass custom connection string - if not passed, then default
' same as MyRst, but allows one to "edit" the reocrdset, and add to reocrdset and then commit the update.
If strCon = "" Then
strCon = GetConstr()
End If
Dim mycon As New SqlConnection(strCon)
oReader = New SqlDataAdapter(strSQL, mycon)
Dim rstData As New DataTable
Dim cmdBuilder = New SqlCommandBuilder(oReader)
Try
oReader.Fill(rstData)
oReader.AcceptChangesDuringUpdate = True
Catch
End Try
Return rstData
End Function
So, now in vb.net, I actually find it is LESS code then even writing + using recordsets in MS-Access VBA code.
However, BEFORE you go down ANY of the above road?
Have you considered using the vb.net data binding features. Data-binding in vb.net means that you do NOT write ANY of the above code. it means that vb.net will do all of the dirty work, and write and setup ALL OF the code for you to edit data on a form. The end result is you don't write any code to update a table.
You do have to use + create a "data set". Once done, then you just drag controls onto the form, and you even get this. So you just drop in a dataset, table adaptor, Binding navagator, and you get this:
Note now the tool bar at the top (and you can place it on teh bottom if you wish). So you get this:
So that WHOLE form was created without having to write ONE line of code. And you can see we have navigation, edits and saves and even the ability to add. So, you can build up a editing form - and it thus becomes similar to say working in MS-Access and ZERO lines of code is required to build the above form.
However, if you ARE going to roll your own code? Then use a data row. That way you can shuffle data to/from the table, and NOT have to use parmaters and SQL update and insert statements - but ONLY have nice clean code in which you shove, or get values from that data row. .net will "write" all the update stuff for you.
I have a winforms applications that has an ms sql server backend. In my database i have lookup tables for like status, and other tables where the data rarely changes. In my application, several forms might use the same lookup tables (Some have a lot of data in them). Instead of loading/filling the data each time the form is open, is there a way to cache the data from the database that can be accessed from multiple forms. I did some searching, but couldnt find the best solution. There is caching, dictionaries, etc. What is the best solution and can you point me to the documentation that discusses it and may even have an example.
Edit:
In my original post I failed to mention that I have a strongly typed dataset and use tableadapters. I want to preload my lookup tables when my application starts, and then have these dataset tables be used throughout the application, on multiple forms without having to fill them on every form.
I have tried creating a class:
Public Class dsglobal
Public Shared EML_StaffingDataSet As EML_StaffingDataSet
Public Shared Sub populateDS()
EML_StaffingDataSet = New EML_StaffingDataSet
End Sub
Public Shared Sub loadskills()
Dim ta As New EML_StaffingDataSetTableAdapters.TSTAFFSKILLTableAdapter
ta.Fill(EML_StaffingDataSet.TSTAFFSKILL)
End Sub
End Class
I run this on a background worker when my application is starting up. So it loads the dataset table. On fill, I can see the datatable has data in it. When I open a form, i want to use the dataset table, but it seems to clear the data out. Not sure if my approach is correct or where my error is.
Edit2:
I have also tried this per comments, but not sure I am doing it correctly. If I am doing it correctly, then how do I use that as a datasource at design time, can i only do that programmatically?
Public Module lookupdata
Private EML_StaffingDataSet As EML_StaffingDataSet
Private skillvalues As List(Of skill)
Public ReadOnly Property skill As List(Of skill)
Get
If skillvalues Is Nothing Then
getskillvalues()
End If
Return skillvalues
End Get
End Property
Private Sub getskillvalues()
skillvalues = New List(Of skill)
EML_StaffingDataSet = New EML_StaffingDataSet
Dim ta As New EML_StaffingDataSetTableAdapters.TSTAFFSKILLTableAdapter
ta.Fill(EML_StaffingDataSet.TSTAFFSKILL)
For Each row As DataRow In EML_StaffingDataSet.TSTAFFSKILL
Dim skill As New skill
skill.skill_id = row("skill_id")
skill.skill_desc = row("skill_desc")
skill.skill_open_ind = row("skill_open_ind")
skillvalues.Add(skill)
Next
End Sub
End Module
Public Class skill
Public Property skill_id As Integer
Public Property skill_desc As String
Public Property skill_open_ind As Boolean
End Class
You might want to consider a lazy loading pattern, like this:
Public Module LookupData
Private statusValues As List(Of LookupValue)
Public Readonly Property Statuses As List(Of LookupValue)
Get
If statusValues Is Nothing Then
GetStatusValues()
End If
Return statusValues
End Get
End Property
Private Sub GetStatusValues()
statusValues = New List(Of LookupValue)
Dim sql = "select key, value from StatusTable"
'TODO: Read the items from the database here, adding them to the list.
End Sub
End Module
Public Class LookupValue
Public Property Key As String
Public Property Value As String
End Class
The idea is that you've got a single instance of LookupData (a Module in VB, there can be only one). Lookup data has a series of Properties, each of which returns a list of values from the database. If the data has already been loaded, it just returns what it has cached. If the data has not been loaded, then the first time it is referenced it retrieves it from the database.
You can consume it elsewhere in your code as follows:
Dim myStatuses = LookupData.Statuses
I can't figure out why my code won't save to my .accdb database.
I am fetching data from a .accdb database file and displaying it in a DataGridView, and then allowing changes to be made to it there. (This is a stock control system.) After making changes, the user is meant to be able to send the data back so it is saved in the .accdb file.
I have looked online everywhere and tried multiple different ways of doing this. This is the way I am currently using to solve the problem, but when running the code it does not save to the .accdb file. (However, it throws up no errors.)
Public Class Database
Dim datatable As DataTable
Dim adapter As OleDb.OleDbDataAdapter
Dim dbCon As New OleDb.OleDbConnection
Dim dbProvider As String = "PROVIDER=Microsoft.ACE.OLEDB.12.0;"
Dim dbRsrc As String = "Data Source =" & System.IO.Directory.GetCurrentDirectory & "/Resources/List.accdb"
Dim binding As BindingSource
Dim cmdBuilder As OleDb.OleDbCommandBuilder
Private Sub Database_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dbCon.ConnectionString = dbProvider & dbRsrc
dbCon.Open()
adapter = New OleDb.OleDbDataAdapter("Select * FROM List", dbCon)
datatable = New DataTable
adapter.FillSchema(datatable, SchemaType.Source)
adapter.Fill(datatable)
binding = New BindingSource
binding.DataSource = datatable
dbCon.Close()
StockTable.DataSource = binding
End Sub
Private Sub SaveBtn_Click(sender As Object, e As EventArgs) Handles SaveBtn.Click
'insert validation here
Try
dbCon.ConnectionString = dbProvider & dbRsrc
dbCon.Open()
cmdBuilder = New OleDb.OleDbCommandBuilder(adapter)
adapter.AcceptChangesDuringUpdate = True
adapter.Update(datatable)
dbCon.Close()
Catch ex As Exception
MsgBox(ex.Message.ToString() & " Save Unsuccessful.")
End Try
End Sub
End Class
Not sure where I'm going wrong - when I hit the 'save' button, it should connect to the database, build a SQL query to update it and then update my datatable + .accdb database, right?
To test it, I've tried editing multiple columns and saving it, but when opening the file it still says the same values as it had before.
Any suggestions/pointers? I'm pretty newbie to VB.NET, learnt it about 3 months ago and only just starting to get fully into it.
Many thanks to the user "jmcilhinney" who helped me to reach this answer. I feel highly stupid at not realising that my code was working.
I used
Debug.WriteLine("Update value: " & adapter.Update(datatable))
Debug.WriteLine("Connection str: " & dbProvider & dbRsrc)
to find that my update command worked, and that in fact the output of my database file was in the /bin/ folder. I didn't realise that it used the /bin/ folder, and was looking in the root folder with the .VB files, etc.
I am new here and only signed up because I desperately need the solution to my problem. I have a VB.NET project that is using a local .MDF file that I have imported into my project. The primary keys are intact so I know that isn't my issue.
I am using Linq-to-SQL to query the database and make changes. On my main form I use a Data Grid View that is populated by a query. I am having an issue with my insert where the query works fine and the DGV gets updated with newly created data, but when I call SubmitChanges() the changes do not get saved to the actual physical database. I am not sure what I am missing or doing wrong.
Here is my code to better assist your educated answer.
Public Class frmCell_Leader
'Reference DataContext
Private db As New MarquardtClassesDataContext()
Private Sub frmCell_Leader_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
FillProductionGrid()
PrepareInsertFields()
End Sub
Private Sub FillProductionGrid()
''''''''''''''''''''''''''''''''''
'E.Salce Last Modified 11.29.2012
'Comments: Working
''''''''''''''''''''''''''''''''''
'Populate DGV
Dim query = From marq In db.tblProductivities
Select
marq.PartNum, marq.Produced, marq.Packed, marq.Issue, marq.StationNum, _
marq.PlanDownTime, marq.UnplannedDownTime, marq.CurDate
dgvProduction.DataSource = query
End Sub
Private Sub PrepareInsertFields()
''''''''''''''''''''''''''''''''''
'E.Salce Last Modified 11.29.2012
'Comments: Working
''''''''''''''''''''''''''''''''''
'Fill Planned Downtime Combo Box
Dim PlannedQuery = From planned In db.tblPlannedDownTimes
Select planned.Plan_ID, planned.Description, planned.Active
Where Active = True
cboPlanned.DataSource = PlannedQuery
cboPlanned.DisplayMember = "Description"
cboPlanned.ValueMember = "Plan_ID"
'Fill UnPlanned Downtime Combo Box
Dim UnPlannedQuery = From unplanned In db.tblUnplannedDownTimes
Select unplanned.Unplan_ID, unplanned.Description, unplanned.Active
Where Active = True
cboUnplanned.DataSource = UnPlannedQuery
cboUnplanned.DisplayMember = "Description"
cboUnplanned.ValueMember = "UnPlan_ID"
End Sub
Private Sub btnAdd_Click(sender As System.Object, e As System.EventArgs) Handles btnAdd.Click
'Add the new Production to database
'Create an productivity object
Dim marqpro As New tblProductivity With {
.PartNum = CShort(txtPartNumber.Text),
.Produced = CShort(txtProduced.Text),
.Packed = CShort(txtPacked.Text),
.Issue = txtIssue.Text,
.PlanDownTime = CShort(cboPlanned.SelectedValue),
.UnplannedDownTime = CShort(cboUnplanned.SelectedValue),
.CurDate = Date.Today}
'insert newly created data
Try
'Submit changes too database
db.tblProductivities.InsertOnSubmit(marqpro)
db.SubmitChanges()
db.Refresh(Data.Linq.RefreshMode.KeepCurrentValues, marqpro)
'Refresh DGV
FillProductionGrid()
MessageBox.Show("Data added successfully")
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message)
End Try
End Sub
End Class
Perhaps you have an .mdf file in your project that is getting copied to the bin/debug folder everytime you build.
Why isn't my SubmitChanges() working in LINQ-to-SQL?
I followed an example on stackoverflow about how to read database records into variables. This is the first time doing this and I feel that I'm close but I'm baffled at this point about the problem.
Here is the link I am referring to:
Visual Basic 2010 DataSet
My code is shown below.
Public Class Form1
' DataSet/DataTable variables
Dim testdataDataSet As New DataSet
Dim dttestdataDataTable As New DataTable
Dim datestdataDataAdapter As New Odbc.OdbcDataAdapter
' Variables for retrieved data
' Dim sSpeed As String = ""
' Dim sFuelprice As String = ""
Dim sSpeed As Integer
Dim sFuelprice As Integer
'Connect to the database
''
'Fill DataSet and assign to DataTable
datestdataDataAdapter.Fill(TestdataDataSet , "TestdataDataSet")
dttestdataDataTable = TestdataDataSet.Tables(0)
'Extract data from DataTable
' Rows is the row of the datatable, item is the column
sSpeed = dtTestdataDataTable.Rows(0).Item(0).ToString
sFuelprice = dtTestdataDataTable.Rows(0).Item(1).ToString
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
result.Text = Val(miles.Text) * sSpeed * sFuelprice
End Sub
End Class
Basically, I am getting declaration errors and I don't understand why since the example I was following clearly declared them. I'm connecting to an Access DB called "testdata.mdb" which contains only 1 record with two fields that I want to use throughout the program. The exanple said to dim the variables for each field as strings but this created more dim errors so I made them into integers and remarked out the original dim statements in the meantime (since they're going to be used in calculations.) The dataadapter and datatable variables also are getting flagged for not being declared when they were earlier in the program. I know this must be a simple thing to fix but I'm just not seeing it.
The form is just a simple thing where the user types in a number and a result is produced by using the numbers read in from the database. In short, I want to be able to do simple calculations with a database within a program and the dim statement thing is getting in the way.
If someone can please clarify what I should do, that would be very much appreciated. Thanks!
When you're trying to learn new technology, it's usually best to work from the outside in. The "outside-most" object in your case seems to be an OdbcConnection object.
Public Class Form1
Const connectionString as String = "Driver={Microsoft Access Driver (*.mdb)};DBQ=c:\bin\Northwind.mdb"
Dim connection As New OdbcConnection(connectionString)
connection.Open()
connection.Close()
end Class
Resolve errors at that level first. Then add a declaration for the data adapter--only for the data adapter--and resolve any errors with that. Repeat until you finish your class.
See OdbcConnectionString, and refer to the connection string web site if you need to.
I apologize for the delay in writing the answer to close off this question and sum it up.
In my case, it dataset is a one row database called testdata and contains 20 fields.
The solution that worked is as follows:
Immediately after the form1_load event, the variables can be immediately written after the dataadapter line:
Me.TestdataTableAdapter.Fill(Me.fooDataSet.testdata)
speed = Me.fooDataSet.testdata(0).speed
fuelprice = Me.fooDataSet.testdata(0).fuelprice
mpg = Me.fooDataSet.testdata(0).mpg
Then just DIM the variables to whatever you want them to be (in this case, speed is an integer, fuelprice is a decimal and MPG is a decimal) right after the PUBLIC CLASS statement at the top of your form's code.
You can then manipulate the variables in calculations after a button click as such:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
fuelcost = CDec((miles.Text/ mpg) * fuelprice)
txtfuelcost.Text = fuelcost.ToString
End Sub
Thank you all for your responses!