How can I allow multiple users to access/edit a microsoft access database? - vb.net

Now I know right off the bat that Microsoft access isn't the ideal client for multiple users accessing it but it's the only one I've got right now. I have built a small program as a sort of inventory management system. There are currently three users that will be using it regularly and at the same time. One issue I am running into with this is that sometimes the database will not be accessible and will give an error stating that the file is already in use by "so and so" user. The other issue is that I'm getting a similar error every now and then where it states "The database has been placed in a state by user on machine that prevents it from being opened or locked". I am connecting to the database through an ACE OLEDB connection using the line below
con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=P:\Tool & Cutter Grinding\Tool Cutter Database.accdb;Persist Security Info = False"
I have also changed some of the settings in the actual access database such as:
Enable all macros
Add the folder the database is in to the trusted locations list
Confirm that the database is set to open in shared mode by default
I don't know if there is something small I've missed or a setting I need to change but as of yet, the problem is still persisting.
Below is an example of how I am using the database. I am using string based SQL commands but am not too familiar with DataSet/DataTable/etc. items, so I may be doing something incorrectly.
'close connection from any previous session
con.Close()
'clear dataset so as not to append data
ds.Clear()
'Select SQL query that selects ALL records from a table
Dim str As String = "SELECT * FROM " & "[" & table & "]" & ""
con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=P:\Tool & Cutter Grinding\Tool Cutter Database.accdb;Persist Security Info = False"
'use try catch statement to open the connection
Try
con.Open()
Catch ex As Exception
MsgBox(Convert.ToString(ex))
End Try
'use try catch statement to add a table (dt) to the dataset (ds) in order to store values
Try
ds.Tables.Add(dt)
Catch ex As Exception
End Try
'create new dataadapter object using the sql string from above and the connection created above
da = New OleDbDataAdapter(str, con)
'create new command builder in order to excecute the SELECT SQL statement using the dataadapter created (da)
'specify prefix and suffix for cb
Dim cb = New OleDbCommandBuilder(da) With {
.QuotePrefix = "[",
.QuoteSuffix = "]"
}
'use try catch statement to fill the datatable (dt) using the dataadapter (da)
Try
da.Fill(dt)
Catch ex As Exception
MsgBox(Convert.ToString(ex))
End Try
'set the datasource of the datagridview to the datatable
dgv.DataSource = dt.DefaultView
'close the connection to the database
con.Close()

Go to your Back-End Access DB file. File > Options > Client Settings. For your Use Case No Locks should be fine, but Edited record setting will work as well if you need it

but its [sic] the only one I've got right now
Actually, it's not.
Have a look at SQL Server Compact. It's free, it's small and it handles multiple users with aplomb.
You can add all the references you need using NuGet.

Related

Can't access Local SQL database manually by connection string in VB.NET using Visual Studio

I have a project set up with 3 separate tables. I used the built-in designer from Visual Studio.
The tables contain
Students
Courses
Tests in each course
All the tables share a studentnumber.
I have no problem getting and accessing the data true different tableadapters and corresponding bindingsources automatically generated by Visual Studio when I "drag and drop" them on the forms. I also am able to use the query builder to get the data I need from each table.
My problem occurs when I try to access the database manually via connection string.
I get this error:
Cannot attach file local path\HovedDatabase.mdf as database Outcomes because the file is already in use for database local path\HovedDatabase.mdf
This is the code I have:
Private Sub FormPrøver3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'StudentDataSet.StudentTabell' table. You can move, or remove it, as needed.
Me.StudentTabellTableAdapter.Fill(Me.StudentDataSet.StudentTabell)
Me.StudentTabellTableAdapter.Connection.Close()
Get_Data_Manualy_Fag()
End Sub
Private Sub Get_Data_Manualy_Fag()
Try
'Create variabals for inputcontainer
Dim Studnr As String = Me.StudentnrLabel1.Text
'Create a connection to the DataBase
Dim myConn As SqlConnection
myConn = New SqlConnection("Initial Catalog=OutComes;Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\HovedDatabase.mdf;Integrated Security=True")
'Create a Command object.
Dim myCmd As SqlCommand
myCmd = myConn.CreateCommand
myCmd.CommandText = "SELECT Fag FROM Fag3Tabell WHERE Fag = #Studnr"
myCmd.Parameters.AddWithValue("#Studnr", Studnr)
'Open the connection.
myConn.Open()
'Process the answer
Dim myreader As SqlDataReader
myreader = myCmd.ExecuteReader
'Traverse the DataSet and Display :
Dim i As Integer = 0
Do While myreader.Read()
Me.ComboBox1.Items.Add(myreader.GetString(i))
i = i + 1
Loop
'Close the connection
myConn.Close()
'Handle errors
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
I set up a similar project with a similar LocalSQL database. I have done nothing in Visual Studio other than creating the database with the same tables.
Here I have no problem connecting to the database via manual connection string.
My question is: why can't I access the local DB with a connection string in the first project?
You haven't posted your other connection string, but it looks like AttachDbFilename may be the problem. The DB will already be attached, this option is only meant to be used in single-user mode (one connection only).
Best bet is to permanently attach the DB to the LocalDB instance if that is what you are using the whole time.

Vb.net Could not save, locked by another user

I am having the problem that about when i try to update a picture, and i click save the error message said that "could not save, locked by another user. where error i did? Sometimes I could update, but sometimes not, why?
And I realize that I have to open Access file and close it then will work.
The error line is cmd.ExecuteNonQuery().
Dim con = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source =..\room.accdb")
Dim ms As New MemoryStream
Dim arrimg As Byte()
Me.PictureBox1.Image.Save(ms, Imaging.ImageFormat.Png)
arrimg = ms.GetBuffer()
ms.Read(arrimg, 0, ms.Length)
Dim sql As String = "UPDATE Userss SET profilepicture =#profilepicture WHERE studentid=" & Form1.txtStuID.Text & ";"
Dim cmd As New OleDbCommand
con.open()
cmd = New OleDbCommand(sql, con)
Dim photo As OleDbParameter = New OleDbParameter("#profilepicture", SqlDbType.Image)
photo.Value = arrimg
cmd.Parameters.Add(photo)
cmd.ExecuteNonQuery()
MessageBox.Show("Profile picture saved.")
con.close()
The 'locked by another user' is a vague message by MS Access since it can be due to a couple of different reasons. It's not to be confused by a specific reason (such as always meaning a table lock). It can be that or it can be the *.ldb file itself or it can be form/table design or even permissions related. However, in your scenario, you are getting it since you have opened the db on MS Access as you mentioned. Opening the db / tables, usually put a lock on the tables.
When you open a record or the form (or table structure) is not designed optimally or someone opens the mdb/accdb who doesn't have both read and write permissions to the folder and file. This error has to do with the *.ldb file associated with the *.mdb/accdb file which is actually what is 'locking' and causing the error.
Some options can be considered, like;
using a NO LOCK in your update statement, but that might not be the best one.
make sure all your connections are well disposed after use.
use using blocks for your objects that implement IDisposable.
you can also read a bit about DEADLOCKS, it might help avoid locks
This should work:
Dim arrimg As Byte()
Using ms As New MemoryStream
Me.PictureBox1.Image.Save(ms, Imaging.ImageFormat.Png)
arrimg = ms.GetBuffer()
ms.Read(arrimg, 0, ms.Length)
End Using
Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source =..\room.accdb")
con.Open()
Using cmd As New OleDbCommand("UPDATE Userss SET profilepicture = #profilepicture WHERE studentid = #studentId;", con)
Dim studentID As New OleDbParameter("#studentId", Form1.txtStuID.Text)
cmd.Parameters.Add(studentID)
Dim photo As New OleDbParameter("#profilepicture", SqlDbType.Image)
photo.Value = arrimg
cmd.Parameters.Add(photo)
cmd.ExecuteNonQuery()
MessageBox.Show("Profile picture saved.")
End Using
con.Close()
End Using
From the code i can see you mix presentation and data access logic, you should probably limit each of your feature to DAL methods so it's easier to find where your DB connection stay open.
With Using like this you can easily avoid to manually dispose the objects and you can be sure the connection will be closed even with exceptions.
Always use parameters and check for disposable object (like MemoryStream).

Opening SQL connection

I have inherited software to maintain. The previous version used a third party Datagridview substitute that isn't compatible with versions of Windows from Vista on. In attempting to put Datagridviews in I have run into a problem with connecting to the database.
I am trying to make a small program to play around with connection and SELECT outside of the original software so I can further understand what I am doing and without going through the full process of using the original software to get to the testing point.
Private Shared Function GetData(ByVal sqlCommand As String) As DataTable
Dim table As New DataTable()
Dim connectionString As String = "Data Source=.\SQLExpress;Integrated Security=true;" _
& "AttachDbFilename=C:blah\blah\blah.mdf;User Instance=true;"
Using con = New SqlConnection(connectionString)
Using command = New SqlCommand(sqlCommand, con)
Using da = New SqlDataAdapter(command)
da.Fill(table)
End Using
End Using
End Using
Return table
End Function
My SQL command is a simple "Select * FROM Setup" and the rest of the program is form loads, imports, and DataGridView formatting. I don't think it affects the SQL part and would be cumbersome to include here.
This results in what appears to be a closed connection.
![Connection Property] http://i.imgur.com/b5V3Qy5.png
This is a screenshot of my SQLExpress which might help diagnose connection problems.
![SQL Properties] http://i.imgur.com/bakBq5D.png
I've blurred out the computer name in grey, but I did notice that there was another computer name in pink. I don't know what it means other than maybe this database was originally created on another computer and has been copied and pasted.
Finally this is the connection string that the original software used:
"Data Source=.\SQLExpress;AttachDbFilename=C:\blah\blah\blah.mdf;Trust_Connection=Yes;"
I have also tried:
"Data Source=.\SQLExpress;AttachDbFilename=C:\blah\blah\blah.mdf;Trusted_Connection=Yes;User Instance=true"
Finally, this is my exception:
"An attempt to attach an auto-named database for file C:\blah\blah\blah.mdf failed. A database with the same name exists, or specified file cannot be opened, or it is located on UNC share."
I got my alternate connection strings from www.connectionstrings.com.
You are missing the Open() command.
con.Open()
Full code listing. (Also a good idea is to wrap your code in a Try.... End Try block).
Private Shared Function GetData(ByVal sqlCommand As String) As DataTable
Dim table As New DataTable()
Dim connectionString As String = "Data Source=.\SQLExpress;Integrated Security=true;" _
& "AttachDbFilename=C:blah\blah\blah.mdf;User Instance=true;"
Using con = New SqlConnection(connectionString)
conn.Open()
Using command = New SqlCommand(sqlCommand, con)
Using da = New SqlDataAdapter(command)
da.Fill(table)
End Using
End Using
End Using
Return table
End Function

Cannot connect to dbf file

I'm trying to connect to to a foxpro table (.dbf) from a test vb.net form.
I recieve an OleDbException with the message "Cannot open file c:\emp\emptbl.dbf"
Have tried with both of the following connection strings:
Provider=VFPOLEDB.1;Data Source=C:\emp\emptbl.dbf
from the MSDN article here
Provider=vfpoledb;Data Source=C:\emp\emptbl.dbf;Collating Sequence=machine;
from connectionstrings.com
The latter seems to be the type to use when connecting to a single table, but the same exception is thrown regadless of which is used.
I can open and perform the same query okay in visual foxpro 6.0.
Here's my code:
Dim tbl As DataTable = New DataTable()
Using con = New OleDbConnection(conString)
cmd = New OleDbCommand() With {.Connection = con, .CommandType = CommandType.Text}
Dim sSQL As String = "SELECT * FROM(EMPTBL)"
cmd.CommandText = sSQL
Dim adp As OleDbDataAdapter = New OleDbDataAdapter(cmd)
Dim ds As DataSet = New DataSet()
con.Open()
adp.Fill(ds)
con.Close()
If (ds.Tables.Count > 0) Then
tbl = ds.Tables(0)
End If
End Using
Return tbl
The OleDB provider should only connect to the PATH where the tables are... not the actual file name. Once you connect to the PATH, you can query from ANY .Dbf file that is located in it
Provider=VFPOLEDB.1;Data Source=C:\emp
select * from emptbl where ...
You can also look at other connection string settings at
ConnectionStrings.com
UPDATE per comment.
It appears you are getting closer. with your attempt without the () parens. In VFP, within parens, it interprets that as "look for a variable called EMPTBL", and from its value is the name of the table to query from. Not something you would need to apply via OleDB connection.
Now, cant open the file is another. Is it POSSIBLE that another application has the table open and the file is in exclusive use? and thus can not be opened by the .net app too? Even for grins, if you open VFP, and just do a simple create table in the C:\Emp folder and put a single record in it, then you know no other program will be using it as it is a new file. Quit out of VFP and try to query THAT table. There should be no locks, no other program is expecting it, so it should never be opened by anything else and you should be good to go.

ADO.Net Synchronization & SQL CE

I've succesfully synchronized both source and local db using the local database cache item in VS 2008.
However, I need to access the SQL CE db directly from within another dll/process, and without using a dataset. The reason being that my business object code does not use datasets.
The final code wouldlook something like this:
Dim conn As New SqlServerCe.SqlCeConnection("Data Source=C:\Development\UserDirectory\UserDirectory.DBSyncher\ProfDir.sdf;Persist Security Info=False;")
Dim cmd As New SqlServerCe.SqlCeCommand("Select EmailAddress from Employees Where ID=23", conn)
Dim returnString As String = ""
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
returnString = cmd.ExecuteScalar
conn.Close()
cmd = Nothing
I notice something very strange using a dataset the synchronized changes are shown but accessing the CE database file directly returns old data - no synched data whatsoever.
What am I missing? Any help would be greatly appreciated.
Figured it out!
Forgot that CE is in process, thus it copies the database file(.sdf) to the Debug folder. You have to to reference that database not the one in your project. DOH!