I'm using Access 2007 and C# to learn Databases. So far it's been rough but I've been able to handle things relatively well. What I need to do though is to query a my database table Accounts for the Amount of money a user has based on their pin. I've placed a button on the Windows Form I am using that will query the database on click. When I run/click the button as per normal I recieve the following error.
Essentially my question is this: How would I go about setting the permissions up so that my program can freely access the Access Database I have?
My Exception Error:
Exception: System.Data.OleDb.OleDbException: The Microsoft Office Access database engine cannot open or write to the file 'C:\Users\Public'. It is already opened exclusively by another user, or you need permission to view and write its data.
My code:
public partial class frmPin : Form
{
static string connString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Public;Persist Security Info=True";
static private int pin = 11; //The First Pin in my records, for debugging I inserted it directly.
static string selectStatement = "SELECT Amount FROM Accounts WHERE(PIN=" + pin + ")";
OleDbConnection conn = new OleDbConnection(connString);
OleDbCommand cmd = new OleDbCommand(selectStatement);
public frmPin()
{
InitializeComponent();
}
private void btnQry_Click(object sender, EventArgs e)
{
try
{
conn.Open();
OleDbDataReader reader = cmd.ExecuteReader(); // executes query
while (reader.Read()) // if can read row from database
{
txtBx.Text = reader.GetValue(1).ToString();
}
}
catch (Exception ex)
{
txtBx.Text = "Exception: " + ex; // Displays Exception
}
finally
{
conn.Close(); // finally closes connection
}
}
"C:\Users\Public" needs to be changed to the actual path of the *.mdb file you want to access:
"C:\Users\Public.mdb"
OR
"C:\Users\Public\Something.mdb"
Depending on the name of your database:
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin;Password=;
Or it may be an *.accdb file. Such as:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccess2007file.accdb;Persist Security Info=False;
See http://www.connectionstrings.com/access-2007 and http://www.connectionstrings.com/access
Also, sometimes you will get this kind of problem if you have the file open in another program like Access 2007, the file is marked as Read Only, or the security permissions are such that you don't have Read or Write Access. Note that if you set a "Deny" permission (in the filesystem/NTFS) for a group like Users, then it will override all other permissions, such that an Administrator would be effected by the Deny permission.
Edit: Thanks for comments, added a little clarification.
Related
I have read the numerous posts on why you should give the using statement preference over manually doing .Open() then .Close() and finally .Dispose().
When I initially wrote my code, I had something like this:
private static void doIt(string strConnectionString, string strUsername)
{
SqlConnection conn = new SqlConnection(strConnectionString);
try
{
conn.Open();
string strSqlCommandText = $"CREATE USER {strUsername} for LOGIN {strUsername} WITH DEFAULT SCHEMA = [dbo];";
SqlCommand sqlCommand = new SqlCommand(strSqlCommandText, conn);
var sqlNonReader = sqlCommand.ExecuteNonQuery();
if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
conn.Close();
conn.Dispose();
}
}
and this works... no problem. but only ONCE.
so, if I do something like this:
private static void doItLots(string strConnectionString, string strUsername)
{
for(int i=0; i<10; i++)
{
doIt(strConnectionString, $"{strUsername}_{i}");
}
}
it works the FIRST time when i=0, but any subsequent iterations fail with Cannot open database "myDbName" requested by the login. The login failed.
However, if I go back and comment out the conn.Dispose(); line, then it works fine on all iterations.
The problem is simply that if I want to do the .Dispose() part outside of the method, then I am forced to pass a SqlConnection object instead of simply passing the credentials, potentially making my code a bit less portable and then I need to keep the connection around longer as well. I was always under the impression that you want to open and close connections quickly but clearly I'm misunderstanding the way the .Dispose() command works.
As I stated at the outset, I also tried doing this with using like this...
private static void doIt(string strConnectionString, string strUsername)
{
using (SqlConnection conn = new SqlConnection(strConnectionString))
{
try
{
conn.Open();
string strSqlCommandText = $"CREATE USER {strUsername} for LOGIN {strUsername} WITH DEFAULT SCHEMA = [dbo];";
SqlCommand sqlCommand = new SqlCommand(strSqlCommandText, conn);
var sqlNonReader = sqlCommand.ExecuteNonQuery();
if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
conn.Close();
}
}
}
and this does the exact same thing as the initial code with .Dispose() called manually.
Any help here would be greatly appreciated. I'd love to convert to the using statements but having trouble figuring out how to write reusable methods that way...
UPDATE:
I have narrowed it down a bit. The issue is NOT the iterations or making the calls over-and-over again. But I am still getting an access error. Here is the code:
string strConnectionString = $#"Data Source={StrSqlServerDataSource};Initial Catalog={StrDatabaseName};User id={StrSqlServerMasterUser};Password={StrSqlServerMasterPassword}";
using (SqlConnection connUserDb = new SqlConnection(strConnectionString))
{
try
{
Utility.Notify($"Connection State: {connUserDb.State.ToString()}"); // Responds as 'Closed'
connUserDb.Open(); // <-- throws error
Utility.Notify($"Connection State: {connUserDb.State.ToString()}");
Utility.Notify($"MSSQL Connection Open... Adding User '{strUsername}' to Database: '{strDatabaseName}'");
string sqlCommandText =
//$#"USE {StrDatabaseName}; " +
$#"CREATE USER [{strUsername}] FOR LOGIN [{strUsername}] WITH DEFAULT_SCHEMA = [dbo]; " +
$#"ALTER ROLE [db_datareader] ADD MEMBER [{strUsername}]; " +
$#"ALTER ROLE [db_datawriter] ADD MEMBER [{strUsername}]; " +
$#"ALTER ROLE [db_ddladmin] ADD MEMBER [{strUsername}]; ";
using (SqlCommand sqlCommand = new SqlCommand(sqlCommandText, connUserDb))
{
var sqlNonReader = sqlCommand.ExecuteNonQuery();
if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername} ({sqlNonReader})");
}
result = true;
}
catch (Exception ex)
{
Utility.Notify($"Creating User and Updating Roles Failed: {ex.Message}", Priority.High);
}
finally
{
connUserDb.Close();
Utility.Notify($"MSSQL Connection Closed");
}
}
return result;
}
The error I am getting here is: Cannot open database requested by the login. The login failed.
One clue I have is that prior to this, I was running this same code with two changes:
1) uncommented the USE statement in the sqlCommandText
2) connected to the Master database instead
When I did that, it didn't work either, and instead I got this error: The server principal is not able to access the database under the current security context.
If I go into SSMS and review the MasterUser they are listed as db_owner and I can perform any activities I want, including running the command included in the code above.
I rewrote all the code to make use of a single connection per the recommendations here. After running into the "server principal" error, I added one more connection to attempt to directly connect to this database rather than the master.
UPDATE 2:
Here is another plot twist...
This is working from my local computer fine (now). But, not (always) working when run from an Azure Webjob that targets an Amazon Web Services (AWS) Relational Database Server (RDS) running MSSQL.
I will have to audit the git commits tomorrow, but as of 5p today, it was working on BOTH local and Azure. After the last update, I was able to test local and get it to work, but when run on Azure Webjob it failed as outlined above.
SqlConnection implements IDisposable. You don't call dispose or close.
try{
using (SqlConnection conn = new SqlConnection(strConnectionString))
{
conn.Open();
string strSqlCommandText = $"CREATE USER {strUsername} for LOGIN {strUsername} WITH DEFAULT SCHEMA = [dbo];";
SqlCommand sqlCommand = new SqlCommand(strSqlCommandText, conn);
var sqlNonReader = sqlCommand.ExecuteNonQuery();
if (sqlNonReader == -1) Utility.Notify($"User Added: {strUsername}");
}}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
I am having below piece of code where i try to connect to IBM's Informix database.
public void MakeConnection()
{
string ConnectionString =
#"Database=databasename;
Host=ipaddress;
Server=servername;
Service=port;
Protocol = olsoctcp;
UID = userid;
Password = password;";
IfxConnection conn = new IfxConnection();
conn.ConnectionString = ConnectionString;
try
{
conn.Open();
}
catch (IfxException ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
Getting below error on opening a connection.
ERROR [HY000] [Informix .NET provider][Informix]Database locale information mismatch.
When i try connecting using windows ODBC Data sources application, by creating a new user data source under User DSN and providing all necessary values under each section of Informix ODBC driver setup, i am able to connect successfully.
All i understand is that the client application's and database's Database Locale value should be same for proper query execution, and i have tried using en_US.57372 and en_US.UTF8 DB Locale while configuring in user DSN's which worked pretty well. I am posting here a image for better understanding.
Appreciate if anyone can help me in knowing where i can find DB Locale configured for in an Informix database and also in detail on what actually causes for this error.
Finally able to connect to database from test application!. Okay here we go,
Step 1: First we need to find what Database locale that database allows us to use? so following #Luis Marques way as he mentioned in comment section, found that Database Locale used is en_US.57372, also en_US.UTF8 is supported.
Step 2: By default, connection object's client locale and database locale property values will be whatever default value was set when Informix ODBC driver was installed.
Slightly modified my test app code as below,
public void MakeConnection()
{
string ConnectionString = "Database=databasename;Host=ipaddress;Server=servername;Service=port;Protocol = olsoctcp; UID = userid; Password = password;";
IfxConnection conn = new IfxConnection();
conn.ConnectionString = ConnectionString;
conn.ClientLocale = "en_US.UTF8";
conn.DatabaseLocale = "en_US.UTF8";
try
{
conn.Open();
}
catch (IfxException ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
So manually assigning client and database locale values for connection object with what we have got in step 1 solved the issue.
I have a program which is supposed to open, edit, create and save access databases. For saving I copy an empty database with just the tables (just to avoid going through the hassle of creating every table and column etc) and try to fill it with values via the TableAdapterManager.UpdateAll method.
string _TemplateConnectString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};";
_connection = new OleDbConnection(string.Format(_TemplateConnectString, dlg.FileName));
_connection.Open();
DataSet1TableAdapters.TableAdapterManager tam=new TableAdapterManager();
tam.Connection = _connection;
try
{
tam.UpdateAll(dataset);
}
catch (System.Exception ex)
{
MessageBox.Show("Update failed");
}
It finishes with no exceptions but the values don't get inserted into the new database.
Also as far as I know the UpdateAll method only updates modified row so if I open some db and it inserts it's rows, it will not take them into account even though there are not in the database that I am trying to fill.
I have also tried filling the database with the ADODB and ADOX extensions but all the solutions I found with those was a lot of hardcoding and no regards for hierarchy, keys, etc.
Is there a way to force insert everything in the new database?
Is your template database in the Visual Studio project directory? It might have something to do with Visual Studio copying the database to the bin/debug or bin/release folder...
Try to use the right Data source database name, here an
example with an excel file:
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=c:\somepath\ExcelFile.xls;" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"";"
A clumsy solution but it works. I iterate the tables of the dataset and save the via an sql string generator like this:
void SaveTable(DataTable dt)
{
string[] inserts;
try
{
inserts = SqlHelper.GenerateInserts(dt, null, null, null);
foreach (string s in inserts)
{
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = s;
cmd.Connection = _connection;
int n = cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
SaveOk = false;
}
}
I found the SqlHelper somewhere on this site, but completely lost where, unforunately. So here is the pastebin with it https://pastebin.com/iCMVuYyu
I am trying to develop a simple user management system for the admin of the web application. I am using ASP.NET Wizard Control for this task.
I just put a TextBox for writing the username and when the admin clicks on the Next button, the system should check if the username existed in the database or not. If it is existed, the system should display his information in a placeholder for the admin.
I am struggling with this task. I did the following in the code-behind:
//For checking the user
if (Request.QueryString["Username"] != null)
{
String strUserName = Request.QueryString["Username"];
//Check userName Here
String strReturnStatus = "false";
if (CheckUsername(Request.QueryString["Username"]) == true)
{
strReturnStatus = "true";
}
Response.Clear();
Response.Write(strReturnStatus);
Response.End();
}
Now, I think to create a second method called CheckUsername which I don't know what I should put it inside it:
private bool CheckUsername(string p)
{
//throw new NotImplementedException();
}
It may seem that this question is simple or stupid, but I am a new developer and I could not be able to find a simple resource that could help me in this issue particularly.
I believe the following method is what you're after:
private bool CheckUsername(string username)
{
string connString = "";
string cmdText = "SELECT COUNT(*) FROM Users WHERE Username = #username";
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open(); // Open DB connection.
using(SqlCommand cmd = new SqlCommand(cmdText, conn))
{
cmd.Parameters.AddWithValue("#username", username)); // Add the SQL parameter.
int count = (int)cmd.ExecuteScalar();
// True (> 0) when the username exists, false (= 0) when the username does not exist.
return (count > 0);
}
}
}
You can fill in the blanks (e.g specify a connection string connString and modify cmdText). The SQL query I specified in cmdText is under the assumption of a typical user management system where you have common table names and columns; Users (table) and Username (column). It's hard to justify as you haven't specified the structure. Modify it to suit your applications needs.
The method of counting how many records exist is quite common in most cases. I frequently use that method of checking/validating things as I see fit.
Further information about the code (classes) I used in my example above:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.aspx
I also advise you read about data access (not that link). I'll leave you to that.
I adjust some point in your code:
if (!string.IsNullOrEmpty(Request.QueryString["Username"]))
{
---
---
if (CheckUsername(Request.QueryString["Username"]))
{
---
---
}
Refer to this link as tutorial for your task: http://www.codeproject.com/KB/database/sql_in_csharp.aspx
I am attempting to create a quiz for my C# program using an Access database to hold the question and answers.
In the database table, the questions are in one column, and the answers are in another column. In essence, this is what I would like to happen:
The form loads, and as this happens a question randomly chosen from the database appears on that form. The question itself will be displayed using the label.
Here is my code:
private void WindowsAnalysisQuiz_Load(object sender, EventArgs e)
{
//declare connection string using windows security
string cnString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\Hannah\\Desktop\\\\WindowsAnalysisQuiz.accdb";
//declare Connection, command and other related objects
OleDbConnection conGet = new OleDbConnection(cnString);
OleDbCommand cmdGet = new OleDbCommand();
try
{
//open connection
conGet.Open();
cmdGet.CommandType = CommandType.Text;
cmdGet.Connection = conGet;
cmdGet.CommandText = "SELECT Question FROM WindowsAnalysisQuiz ORDER BY rand()";
label1.Text = cmdGet.CommandText["Question"];
conGet.Close();
}
catch (Exception ex)
{
//display generic error message back to user
MessageBox.Show(ex.Message);
}
finally
{
//check if connection is still open then attempt to close it
if (conGet.State == ConnectionState.Open)
{
conGet.Close();
}
}
}
}
I am getting a problem at the point where I am trying to assign a random question to be displayed in my label.
As an aside, is this method of using a database to store the questions and answers doable?
Thanks
the function you mean is rnd(), not rand().
but i´m not sure if this is possible via the oledb driver.
One solution is to have an Autonumber field in your questions table. Then you can generate the random value in your code, and then query based on the randomly chosen ID number. If, for instance, your questions were numbered 1 to 100, you'd limit the range of your generated random number to that range.