How to solve the SQLite "Database is locked" in C#? - c#

When I update some data, sometimes it throws a exception: Database is locked.
The code below:
public int DisableSalesBySalesID(string SalesID)
{
int count = 0;
try
{
using (SQLiteConnection conn = new SQLiteConnection(ConnectionString))
{
conn.Open();
string sql = #"update SalesMaster set Disabled = '1' where SalesID=#SalesID";
using (SQLiteCommand cmd = new SQLiteCommand(sql, conn))
{
cmd.Parameters.Add(new SQLiteParameter("#SalesID", SalesID));
count = cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
}
return count;
}
And, it depends on SalesID. Some SalesID will be OK, but the others will make the exception. Why?

a common cause is that you have a dangling sqlcommand. sqlcommands hold locks on the database. same for sqlreaders. Make sure they are all in using blocks

Related

I didn't get error when try to connect SQL Server

I have a Virtual Machine in Windows Azure with SQL Server 2016. This VM has a firewall with Azure, where I allow the IP to connect to the server. And also my project is an ASP.NET Web API 2 with ADO.NET for Data Access Layer.
The thing is all set; everything is working fine (Good!). But If I try to connect from another place with an IP that is not added to the firewall rules, I don't get any error, only still to try to execute the command. Normally if I use the SQL Managment I get an error.
This is my parameter in my connection string
Server=vm.XXXXXX.azure.com;Database={database};User ID={userid};Password={password};Encrypt=True;TrustServerCertificate=True;Connection Timeout=300;ConnectRetryCount=4;ConnectRetryInterval=1
So, this is extract code that I executed:
using (SqlConnection dbConnection = new SqlConnection(myCString))
{
using (SqlCommand dbCommand = new SqlCommand())
{
string queryString;
queryString = "SELECT * FROM table WHERE (ID = #ID) ";
dbCommand.Parameters.Add(Utilities.GetSQLParameter("ID", 1234, SqlDbType.VarChar));
dbCommand.CommandText = queryString;
dbCommand.Connection = dbConnection;
dbConnection.Open();
using (SqlDataReader dr = dbCommand.ExecuteReader())
{
if (dr.Read())
{
Value = dr[Field].ToString();
}
else
{
Value = "";
}
}
}
}
In summary, I want to get the error if I cannot find the VM because the firewall is blocking the access.
The connection failure occurs at dbConnection.Open.
Wrap your code in atry/catch block and treat the error if it occurs.
A list of available catchable exceptions can be found at https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.open(v=vs.110).aspx
try
{
dbConnection.Open();
using (SqlDataReader dr = dbCommand.ExecuteReader())
{
if (dr.Read())
{
Value = dr[Field].ToString();
}
else
{
Value = "";
}
}
}
catch(Exception ex)
{
//Do some treatment
}
finally
{
//If connection has been opened, close it.
if(dbConnection.ConnectionState == ConnectionState.Open)
{
dbConnection.Close();
}
}
I will recommend you use USING clear all your "managed resources"
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnStringName"].ToString()))
using (SqlCommand mySqlCommand = new SqlCommand())
{
try
{
conn.Open();
mySqlCommand.Connection = conn;
mySqlCommand.CommandType = CommandType.StoredProcedure;
mySqlCommand.CommandText = "getCities";
mySqlCommand.CommandTimeout = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["ConnectionTimeout"].ToString());
mySqlCommand.Parameters.Add("#param", SqlDbType.VarChar).Value = param;
da.SelectCommand = mySqlCommand;
da.Fill(ds, "cities");
}
catch (Exception ex)
{
// LOG HERE the errors
}
} // end using

Select those emails from db if they wanted to get an email

I am developing a system that heavily relies on emailing, I'm trying to determine if users wanted to get notified or not.
User details are stored in SQL Server Express. I want to check which registered users wanted to receive and get their emails from the database. Is this possible?
So far I got this far:
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = "SELECT COUNT(*) FROM [UserTable] WHERE ([price] = #price)";
command.Parameters.AddWithValue("#price", "10.000");
try
{
connection.Open();
int recordsAffected = command.ExecuteNonQuery();
}
catch (SqlException ex)
{
MessageBox.Show("Error is SQL DB: " + ex);
}
finally
{
connection.Close();
}
}
It returns -1, but I have a 10.000 in one row. And from here I want to save the email addresses of those who has 10.000 on their preferences from the db so I can add it to email list.
So to summarize: Check all rows if some of them has 'yes' and save their 'email' from the same row.
Can someone point me to the right direction? Thank you.
Updated it for #SeM
private void getMailList()
{
using (SqlConnection connection = new SqlConnection("Data Source=DESKTOP-9MMTAI1\\SQLEXPRESS;Initial Catalog=master;Integrated Security=True"))
{
try
{
connection.Open();
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "SELECT COUNT(*) FROM UserTable WHERE price = #price";
cmd.Parameters.Add(new SqlParameter("#price", 10000));
int count = int.Parse(cmd.ExecuteScalar());
}
}
catch (Exception ex)
{
MessageBox.Show("Error is SQL DB: " + ex);
//Handle your exception;
}
}
}
ExecuteNonQuery returning the number of rows that affected only for Update, Insert and Delete statements. In your case, you will always get get -1, because on Select statement ExecuteNonQuery returning -1
So try this:
using(SqlConnection connection = new SqlConnection(connectionString))
{
try
{
connection.Open();
using(SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "SELECT COUNT(*) FROM UserTable WHERE price = #price";
cmd.Parameters.Add(new SqlParameter("#price", 10000));
int count = int.Parse(cmd.ExecuteScalar());
}
}
catch (Exception ex)
{
//Handle your exception;
}
}
As commented above, ExecuteNonQuery does just that - no query results.
Instead:
int recordsAffected = (int)command.ExecuteScalar();

C# SQLConnection to SQL Azure hangs

I've this function, wich updates some records on an Azure SQL DB. The function is called every 10 minutes by a timer:
static public bool CaricaOccupazioniiMae(DataTable dtOccupazioni)
{
using (SqlConnection conn = new SqlConnection(GetSQLAzureConnectionStringiMae()))
{
conn.Open();
using (SqlTransaction tr = conn.BeginTransaction())
{
using (SqlCommand SQLCmd = new SqlCommand("DELETE_t_Promemoria", conn))
{
try
{
SQLCmd.CommandType = CommandType.StoredProcedure;
SQLCmd.Parameters.Add("#CodScuola", mCodiceScuolaiMae);
SQLCmd.Transaction = tr;
SQLCmd.ExecuteNonQuery();
}
catch (System.Exception ex)
{
tr.Rollback();
tr.Dispose();
return false;
}
}
using (SqlBulkCopy SQLCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tr))
{
try
{
SQLCopy.DestinationTableName = "t_Promemoria";
SQLCopy.WriteToServer(dtOccupazioni);
}
catch (System.Exception ex)
{
tr.Rollback();
tr.Dispose();
return false;
}
}
tr.Commit();
}
conn.Close();
}
return true;
}
in two occasions the function just hanged in there... The only thing I'm sure of, is that it haven't reach this block, meanwhile it goes through the conn.open():
SQLCmd.CommandType = CommandType.StoredProcedure;
SQLCmd.Parameters.Add("#CodScuola", mCodiceScuolaiMae);
SQLCmd.Transaction = tr;
SQLCmd.ExecuteNonQuery();
so the logical conclusion is that it hangs in one of those 2 points:
1) SqlTransaction tr = conn.BeginTransaction()
2) SqlCommand SQLCmd = new SqlCommand("DELETE_t_Promemoria", conn);
Have you any clues?
Thanks in advance!
Although I don't see too much wrong with your code, a bit of refactoring might work. If a transaction is not "committed" it will be rolled back by default and a bit less try/catch in there might help avoid resource lock:
using (SqlConnection conn = new SqlConnection(GetSQLAzureConnectionStringiMae()))
{
conn.Open();
using (SqlTransaction tr = conn.BeginTransaction())
{
try
{
using (SqlCommand SQLCmd = new SqlCommand("DELETE_t_Promemoria", conn))
{
SQLCmd.CommandType = CommandType.StoredProcedure;
SQLCmd.Parameters.Add("#CodScuola", mCodiceScuolaiMae);
SQLCmd.Transaction = tr;
SQLCmd.ExecuteNonQuery();
}
using (SqlBulkCopy SQLCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tr))
{
SQLCopy.DestinationTableName = "t_Promemoria";
SQLCopy.WriteToServer(dtOccupazioni);
}
tr.Commit();
}
catch (Exception ex)
{
tr.Rollback();
}
}
conn.Close();
}
return true;
}
If you really need to do both SQL operations (SqlCommand and SqlBulkCopy) in a different transaction, create a new one for each. The way I structured it above does everything in the same transaction and might solve your problem.

update a mySQL table using C#

I have written some C# to update a MySql table but I get an exception every time I call the method ExecuteNonQuery(). I have researched this on the web and every solution I find produces the same error. I have an open connection to the database and the update query to the database is written correctly. The code that I have so far come up with is :
public int executeUpdate()
{
int result = 0;
if (isConnected)
{
try
{
MySqlConnection cn = new MySqlConnection(connection.ConnectionString);
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = cn;
cmd.CommandText = "UPDATE test SET status_id = 1 WHERE test_id = 1";
int numRowsUpdated = cmd.ExecuteNonQuery();
}
catch (MySqlException exSql)
{
Console.Error.WriteLine("Error - SafeMySql: SQL Exception: " + query);
Console.Error.WriteLine(exSql.StackTrace);
}
catch (Exception ex)
{
Console.Error.WriteLine("Error - SafeMySql: Exception: " + query);
Console.Error.WriteLine(ex.StackTrace);
}
}
else
Console.Error.WriteLine("Error - SafeMySql: executeQuery failed. Not connected to DB");
}
Change your try section to the code below:
try
{
using(MySqlConnection cn = new MySqlConnection(connection.ConnectionString))
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = cn;
cmd.CommandText = "UPDATE test SET status_id = 1 WHERE test_id = 1";
cn.Open();
int numRowsUpdated = cmd.ExecuteNonQuery();
cmd.Dispose();
}
}
The connection must be opened before you execute a command. In the example above the command object will immediately be disposed and the connection object will implcitly be closed and disposed when you leave the using section.
I don't see the connection being opened.
Here is an example from MSDN: even inside a using block, they open the connection explicitly
private static void CreateCommand(string queryString,
string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
}
Edit: The principle is the same for MySQL as it is for SQL Server:
public void CreateMySqlCommand(string myExecuteQuery, MySqlConnection myConnection)
{
MySqlCommand myCommand = new MySqlCommand(myExecuteQuery, myConnection);
myCommand.Connection.Open();
myCommand.ExecuteNonQuery();
myConnection.Close();
}

SQL query to scalar result in C#

In some programming contexts getting a scalar value from a sql query is easy:
RowCount = Connection.Execute("SELECT Count(*) FROM TableA").Fields(0).Value
In C#, given a SqlConnection variable conn that is already open, is there a simpler way to do this same thing without laboriously creating a SqlCommand, a DataReader, and all in all taking about 5 lines to do the job?
SqlCommand has an ExecuteScalar method that does what you want.
cmd.CommandText = "SELECT COUNT(*) FROM dbo.region";
Int32 count = (Int32) cmd.ExecuteScalar();
If you can use LINQ2SQL (or EntityFramework) you can simplify the actual query asking to
using (var context = new MyDbContext("connectionString"))
{
var rowCount = context.TableAs.Count();
}
If LINQ2SQL is an option that has lots of other benefits too compared to manually creating all SqlCommands, etc.
There is ExecuteScalar which saves you at least from the DataReader:
static public int AddProductCategory(string newName, string connString)
{
Int32 newProdID = 0;
string sql =
"INSERT INTO Production.ProductCategory (Name) VALUES (#Name); "
+ "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = newName;
try
{
conn.Open();
newProdID = (Int32)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return (int)newProdID;
}
(Example taken from this MSDN documentation article)
You do not need a DataReader. This example pulls back the scalar value:
Object result;
using (SqlConnection con = new SqlConnection(ConnectionString)) {
con.Open();
using (SqlCommand cmd = new SqlCommand(SQLStoredProcName, con)) {
result = cmd.ExecuteScalar();
}
}
Investigate Command.ExecuteScalar:
using(var connection = new SqlConnection(myConnectionString))
{
connection.Open();
using(var command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = mySql;
var result = (int)command.ExecuteScalar();
}
}
If you're feeling really lazy, encapsulate it all in an extension method, like we do.
EDIT: As requested, an extension method:
public static T ExecuteScalar<T> (this SqlConnection connection, string sql)
{
if (connection == null)
{
throw new ArgumentNullException("connection");
}
if (string.IsNullOrEmpty(sql))
{
throw new ArgumentNullException("sql");
}
using(var command = connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
return (T)command.ExecuteScalar();
}
}
Note, this version assumes you've properly built the SQL beforehand. I'd probably create a separate overload of this extension method that took two parameters: the stored procedure name and a List. That way, you could protect yourself against unwanted SQL injection attacks.

Categories

Resources