I am having an intermittent issue with a SqlDataRreader class where I have opened a SqlConnection and its state is OPEN, but when I create a SqlCommand with that SqlConnection, the SqlConnection's state is CLOSED. This only occurs approximately 1 in 10 attempts, and so it might be a timing issue.
Note that rather than putting the connection in a Using block, I open/close the connection independently as I usually execute multiple commands at once, however the issue usually occurs on the first time a command is executed on a connection that has just been opened.
The connection code is:
private SqlConnection sql;
public Result Connect(string database)
{
string connection = Config.environments[Config.environment][database];
try
{
// Create and open the connection
sql = new SqlConnection(connection);
sql.Open();
if (sql == null || sql.State != System.Data.ConnectionState.Open)
return new Result(false, "Connect to Database", "Could not connect to database [" + connection + "]");
return new Result(true, "Connect to Database", "Connected to database [" + connection + "]");
}
catch (Exception e)
{
return new Result(false, "Connect to Database", "Could not connect to database [" + connection + "] " + e.ToString());
}
}
The run command code is:
private DataTable RunSql(string statement)
{
if (sql == null || sql.State != System.Data.ConnectionState.Open)
throw new ScriptException("Cannot execute SQL command, no database connection established [" + statement + "]");
// Create and execute the SQL statement
using (SqlCommand command = new SqlCommand(statement, sql))
{
command.CommandTimeout = Config.sqlTimeout;
try
{
using (SqlDataReader reader = command.ExecuteReader()) // ERROR OCCURS HERE! - sql.State is OPEN, but command.State is CLOSED ???
{
// Check is the reader has any rresults
if (reader.HasRows)
{
DataTable data = new DataTable();
data.Load(reader);
return data;
}
else
{
throw new Exception("No results found for statement: " + statement + ", on server: " + sql.DataSource + ", in database: " + sql.Database);
}
}
}
catch (SqlException)
{
//Log things here
}
throw new ScriptException("Error executing sql command: " + statement);
}
}
The code that reproduces the issue (occasionally):
private DataTable RunSingleCommand(string database, string command)
{
Log(Connect(database));
return RunSql(command);
}
What I can suggest is inside the Connection command before opening the connection , give a condition check to know whether the connection is currently open or not. Only if its in closed mode open the new connection
try
{
// Create and open the connection
sql = new SqlConnection(connection);
if (sql.State != System.Data.ConnectionState.Open)
{
sql.Open();
}
return new Result(true, "Connect to Database", "Connected to database [" + connection + "]");
}
catch (Exception e)
{
return new Result(false, "Connect to Database", "Could not connect to database [" + connection + "] " + e.ToString());
}
Related
Goal:
My goal is to create a MySQL query using C#, and on successful query I'd like to use File.Copy... and vice versa.
This is my current code:
//Try run code
try
{
//Add record to MySQL
using (var conn = new MySqlConnection(ConnectionString.ConnString))
{
using (var cmd = new MySqlCommand("INSERT INTO files (document_name, path, version, section, user_modified, date_modified)" +
" values (#doc, #path, #version, #section, #user, NOW());", conn))
{
conn.Open();
cmd.Parameters.AddWithValue("#doc", docName.Text);
cmd.Parameters.AddWithValue("#path", $"{finalPath}Section {Section.Text}\\{docName.Text}{Path.GetExtension(fileName)}");
cmd.Parameters.AddWithValue("#version", versionNumber.Text);
cmd.Parameters.AddWithValue("#section", Section.Text);
cmd.Parameters.AddWithValue("#user", UserDetails.userId);
cmd.ExecuteNonQuery();
}
}
//Copy file into new directory
File.Copy(fileName, $"{finalPath}Section {Section.Text}\\{docName.Text}{Path.GetExtension(fileName)}");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
Question:
What is a good method to achieve the following..
If MySQL query not successful then do not do anything and stop and return to where the error was.
If MySQL query was successful and File.Copy wasn't (Ran into an error for any reason) - then recover the query, delete whatever was inserted and go back all the way to step one.
How can this be achieved?
Edit 10/06/2020
I have managed to get the following code :
//Try run MySQL query with roll back function if failed.
public void RunTransaction(string myConnString)
{
MySqlConnection myConnection = new MySqlConnection(ConnectionString.ConnString);
myConnection.Open();
MySqlCommand myCommand = myConnection.CreateCommand();
MySqlTransaction myTrans;
// Start a local transaction
myTrans = myConnection.BeginTransaction();
// Must assign both transaction object and connection
// to Command object for a pending local transaction
myCommand.Connection = myConnection;
myCommand.Transaction = myTrans;
try
{
myCommand.CommandText = "INSERT INTO files (document_name, path, version, section, user_modified, date_modified, review_date)" +
" values (#doc, #path, #version, #section, #user, NOW(), NOW() + interval 12 month);";
myCommand.Parameters.AddWithValue("#doc", docName.Text);
myCommand.Parameters.AddWithValue("#path", $"{finalPath}Section {Section.Text}\\{docName.Text}{Path.GetExtension(fileName)}");
myCommand.Parameters.AddWithValue("#version", versionNumber.Text);
myCommand.Parameters.AddWithValue("#section", Section.Text);
myCommand.Parameters.AddWithValue("#user", UserDetails.userId);
myCommand.ExecuteNonQuery();
myTrans.Commit();
}
catch (Exception e)
{
try
{
myTrans.Rollback();
}
catch (MySqlException ex)
{
if (myTrans.Connection != null)
{
Console.WriteLine("An exception of type " + ex.GetType() +
" was encountered while attempting to roll back the transaction.");
}
}
Console.WriteLine("An exception of type " + e.GetType() +
" was encountered while inserting the data.");
Console.WriteLine("Neither record was written to database.");
}
finally
{
myConnection.Close();
}
}
Question..
How would I then implement the File.Copy function to suit my goal?
I have this source.. https://learn.microsoft.com/en-us/dotnet/api/system.io.fileinfo.copyto?view=netcore-3.1
but not sure where to code in my current code?
I'm getting this error when I try to use the button to restore the database:
"An object or column name is missing or empty".
The thing is that I'm using offline database file (.mdf) and when I click ok on this error and press the restore button again, it works like a charm.
There's the code:
private void RestoreButton_Click(object sender, EventArgs e)
{
string database = con.Database.ToString();
if (con.State!=ConnectionState.Open)
{
con.Open();
}
try
{
string sqlStmt2 = string.Format("ALTER DATABASE [" + database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
SqlCommand bu2 = new SqlCommand(sqlStmt2, con);
bu2.ExecuteNonQuery();
string sqlStmt3 = "USE MASTER RESTORE DATABASE [" + database + "] FROM DISK='" + textBox2.Text + "'WITH REPLACE;";
SqlCommand bu3 = new SqlCommand(sqlStmt3, con);
bu3.ExecuteNonQuery();
string sqlStmt4 = string.Format("ALTER DATABASE [" + database + "] SET MULTI_USER");
SqlCommand bu4 = new SqlCommand(sqlStmt4, con);
bu4.ExecuteNonQuery();
MessageBox.Show("Database succesfully restored!");
con.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
There's the full error.
I developed a POS like application and during testing with 2 PCs I didn't encounter any problems with the speed. It's just a simple LAN cable setup between 2 computers. But when I deployed it in a client, it ran slow.
The client has 1 PC serving as the admin and the main server, and there are 2 more PCs serving as the cashier. All connected in a router. The cashiers are connected to the admin's PC (main server) to retrieve, insert, update and delete data. I just want to ask if there are processes that needs to be done in MySQL or are there anything wrong with my codes when connecting to the database.
Here's my sample code for connecting to the database, I doubt having problems with it as this has been the standard in connecting to a database and adding records. Just in case I might bore you with codes, you can simply jump to the second code I posted, I have a comment there asking if the initialization of my class is correct. Thanks everyone!
class DBConnection
{
private MySqlConnection connection;
private MySqlCommand cmd;
private MySqlDataReader dr;
private DataTable tbl;
private MySqlDataAdapter da;
private DataSet ds;
private string connectionString;
private string server;
private string database;
private string uid;
private string password;
private frmNotifOk myNotification;
public DBConnection()
{
Initialize();
}
private void Initialize()
{
server = "CASHIER";
database = "sampledb";
uid = "root";
password = "samplepassword";
connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
private bool OpenConnection()
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server.");
break;
}
return false;
}
}
private void CloseConnection()
{
try
{
connection.Close();
}
catch (MySqlException ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
public void AddRecord(String DBQuery, bool showNotif)
{
string query = DBQuery;
bool notify = showNotif;
try
{
if (this.OpenConnection() == true)
{
cmd = new MySqlCommand(query, connection);
cmd.ExecuteNonQuery();
if (notify)
{
MessageBox.Show("Item successfully added.");
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
finally
{
this.CloseConnection();
}
}
And finally, here's how I use the method in a form:
public partial class frmNewCashier : Form
{
private DBConnection dbConnect;
string sampleDataSource= "SELECT * FROM SampleTable";
public frmNewCashier()
{
InitializeComponent();
//Is this the correct place of initializing my DBConnection class?
dbConnect = new DBConnection();
}
private void frmCashier_Load(object sender, EventArgs e)
{
try
{
dgvSearchItems.DataSource = dbConnect.DatabaseToDatagrid(dgvSearchItemsDataSource);
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
}
I put the initialization of DBConnection class in public frmNewCashier(), is this the correct place or should I put it in Load event or somewhere? I'm thinking if this has bearing to the slowness of database. Aside from this question, do you know anything that I might have missed that causes the slowness?
class DBConnect
{
public MySqlConnection connection;
private string server;
private string database;
private string uid;
private string password;
//Constructor
public DBConnect()
{
Initialize();
}
//Initialize values
public void Initialize()
{
server = "localhost";
database = "db_sea_horses";
uid = "root";
password = " " ;
//password = "123";
string connectionString;
connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
//open connection to database
public bool OpenConnection()
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{ //0: Cannot connect to server.
//1045: Invalid user name and/or password.
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server. Contact administrator");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
return false;
}
}
//Close connection
public bool CloseConnection()
{
try
{
connection.Close();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
}
class DBmethods : DBConnect
{
DataSet dataset2;
public void input_sql(string query)
{
try
{
//open connection
if (this.OpenConnection() == true)
{
//create command and assign the query and connection from the constructor
MySqlCommand cmd = new MySqlCommand(query, connection);
//Execute command
int x = cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
catch(MySqlException myex)
{
MessageBox.Show(ex.Message);
}
}
///////////////////////////////////////////////
///// select
/////////////////////////////////////////////
public DataSet output_sql(string query,String table_name)
{
//Open connection
this.OpenConnection();
DataSet dataset = new DataSet();
MySqlDataAdapter adapter = new MySqlDataAdapter();
adapter.SelectCommand = new MySqlCommand(query, connection);
adapter.Fill(dataset, table_name);
//close Connection
this.CloseConnection();
//return list to be displayed
return dataset;
}
}
}
method calling example
1) insert / update / delete statement
DBmethods dbm = new DBmethods();
dbm.input_sql(" you can excute insert / update / delete query");
2) select statement
DataSet ds = dbm.output_sql("select * from storage_bunkers where job_id LIKE '%" + itemname.Text + "%' ", "storage_bunkers");
DataView myView = ((DataTable)ds.Tables["storage_bunkers"]).DefaultView;
dataGridView1.DataSource = myView;
First, try pinging from client machine to server which has installed SQL server. If it is taking too much time then there's problem with network connection.
If not, put a debug point and try debugging then identify the location that taking too long. Then you will able to get a answer.
Also, do not forget to close each and every db connection after using that.
I'm trying to connect to a SQL Server on a local machine, run a SQL command against it and log the results. The code keeps failing at making the connection to the server.
I can't quite see what I'm doing wrong. Everything I've searched for either doesn't apply to this method or seems to match what I'm doing. I think I have other problems in the code as well, but I can't even get past the SQL connection to test the rest. Here is my code:
string svrConnection = "Server=.\\sqlexpress;Database="+db+";User ID=user;Password=password;";
SqlConnection con;
SqlCommand cmd;
Directory.CreateDirectory("C:\\"db"\\");
FileInfo file = new FileInfo("C:\\script.sql");
string PCS = file.OpenText().ReadToEnd();
con = new SqlConnection(svrConnection);
StreamWriter PCSLog = new StreamWriter(#"C:\\" + db + "\\Log" + db + ".txt");
try
{
con.Open();
cmd = new SqlCommand(PCS, con);
cmd.ExecuteNonQuery();
using (SqlDataReader pcsrdr = cmd.ExecuteReader())
using (PCSLog)
{
while (pcsrdr.Read())
PCSLog.WriteLine(pcsrdr[0].ToString() + pcsrdr[1].ToString() + ",");
}
PCSLog.Close();
cmd.Dispose();
con.Close();
}
catch (Exception ex)
{
MessageBox.Show("Can not open connection !", ex.Message);
}
There are additional problems with your code:
The Lines
cmd.Dispose();
con.Close();
are not guaranteed to execute if an exception occurs.
You call PCSLog.Close AFTER after you have disposed of it
I would suggest this as a better alternative (irrespective of the other comments made here).
string svrConnection = "Server=.\\sqlexpress;Database="+db+";User ID=user;Password=password;";
Directory.CreateDirectory("C:\\" + db + "\\");
FileInfo file = new FileInfo("C:\\script.sql");
string PCS = file.OpenText().ReadToEnd();
try
{
using (SqlConnection con = new SqlConnection(svrConnection))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(PCS, con))
{
cmd.ExecuteNonQuery();
using (SqlDataReader pcsrdr = cmd.ExecuteReader())
using (StreamWriter PCSLog = new StreamWriter("C:\\" + db + "\\Log" + db + ".txt"))
{
while (pcsrdr.Read())
PCSLog.WriteLine(pcsrdr[0].ToString() + pcsrdr[1].ToString() + ",");
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Can not open connection !", ex.Message);
}
I think the issue is your connection string. Try this:
string svrConnection = "Data Source=.\\SQLEXPRESS;Initial Catalog=" + db + ";User Id=user;Password=password;"
Or to get a connection using your windows credentials:
string svrConnection = "Data Source=.\\SQLEXPRESS;Initial Catalog=" + db + ";Trusted_Connection=True;"
Also, ExecuteNonQuery does not run each command separated by GO. You will need to split your query into sections and run each individually.
I am new to C# & I am trying to programatically create & open a SQL Server database.
I have a ASP.NET webapp I am creating & on page load it should pull some data from the database (if the db doesn't exist, it should be created & populated with default data).
PS: does C#'s System.Data.SqlClient use MySQL or SQLite or something else?
Right now I am unsure if my code correctly creates a SQL Server database & if I connect to it correctly.
Can you tell me if my code is correct & how I could improve it?
UPDATE: Error is
"A network-related or instance-specific error occurred while
establishing a connection to SQL Server. The server was not found or
was not accessible. Verify that the instance name is correct and that
SQL Server is configured to allow remote connections. (provider: Named
Pipes Provider, error: 40 - Could not open a connection to SQL
Server)"}"
I have indicated where in the code below the error occurs.
Creating a SQL Server database:
// When I run this function no file seems to be created in my project directory?
// Although there is a ASPNETDB sql database file in my App_Data folder so this maybe it
public static string DEF_DB_NAME = "mydb.db"; // is this the correct extension?
private bool populateDbDefData()
{
bool res = false;
SqlConnection myConn = new SqlConnection("Server=localhost;Integrated security=SSPI;database=master");
string str = "CREATE DATABASE "+DEF_DB_NAME+" ON PRIMARY " +
"(NAME = " + DEF_DB_NAME + "_Data, " +
"FILENAME = " + DEF_DB_NAME + ".mdf', " +
"SIZE = 2MB, MAXSIZE = 10MB, FILEGROWTH = 10%) " +
"LOG ON (NAME = " + DEF_DB_NAME + "_Log, " +
"FILENAME = " + DEF_DB_NAME + "Log.ldf', " +
"SIZE = 1MB, " +
"MAXSIZE = 5MB, " +
"FILEGROWTH = 10%)";
SqlCommand myCommand = new SqlCommand(str, myConn);
try
{
myConn.Open(); // ERROR OCCURS HERE
myCommand.ExecuteNonQuery();
insertDefData(myConn);
}
catch (System.Exception ex)
{
res = false;
}
finally
{
if (myConn.State == ConnectionState.Open)
myConn.Close();
res = true;
}
return res;
}
Here's my connection to the SQL Server database code: I am pretty sure it fails to connect - if I try to use the variable conn, it says the connection is not open. Which could mean that I either failed to connect or failed to even create the db in the 1st place:
private bool connect()
{
bool res = false;
try
{
conn = new SqlConnection("user id=username;" +
"password=password;" +
"Server=localhost;" +
"Trusted_Connection=yes;" +
"database="+DEF_DB_NAME+"; " +
"connection timeout=30");
conn.Open();
return true;
}
catch (Exception e)
{
}
return false;
}
You have probably already got this figured out, but just in case people end up here with the same problem (like I did) here's how I got this working.
Your error is that the SqlConnection is not being opened, because it isn't finding an appropriate server. If you're using the SQL server express edition (as I am) you should set the SqlConnection object like this:
SqlConnection myConn = new SqlConnection("Server=localhost\\SQLEXPRESS;Integrated security=SSPI;database=master;");
Once you resolve that error though, you are going to fail on the next line when you try to execute the query. The "Filename" needs to be separated by single quotes, but you only have one on the end after the extension; you will also need one before.
Also, that is the full physical file path, and it won't use the current directory context, you have to specify a path. Make sure that the location is one which the db server will have access to when it's running, otherwise you will get a SqlException being thrown with an error message along the lines of:
Directory lookup for the file "...\filename.mdf" failed with the operating system error 5 (Access is denied). CREATE DATABASE failed. Some file names listed could not be created.
The code which I ended up using looks like this:
public static string DB_NAME = "mydb"; //you don't need an extension here, this is the db name not a filename
public static string DB_PATH = "C:\\data\\";
public bool CreateDatabase()
{
bool stat=true;
string sqlCreateDBQuery;
SqlConnection myConn = new SqlConnection("Server=localhost\\SQLEXPRESS;Integrated security=SSPI;database=master;");
sqlCreateDBQuery = " CREATE DATABASE "
+ DB_NAME
+ " ON PRIMARY "
+ " (NAME = " + DB_NAME + "_Data, "
+ " FILENAME = '" + DB_PATH + DB_NAME + ".mdf', "
+ " SIZE = 2MB,"
+ " FILEGROWTH = 10%) "
+ " LOG ON (NAME =" + DB_NAME + "_Log, "
+ " FILENAME = '" + DB_PATH + DB_NAME + "Log.ldf', "
+ " SIZE = 1MB, "
+ " FILEGROWTH = 10%) ";
SqlCommand myCommand = new SqlCommand(sqlCreateDBQuery, myConn);
try
{
myConn.Open();
myCommand.ExecuteNonQuery();
}
catch (System.Exception)
{
stat=false;
}
finally
{
if (myConn.State == ConnectionState.Open)
{
myConn.Close();
}
myConn.Dispose();
}
return stat;
}
Use this code,
internal class CommonData
{
private static SqlConnection conn;
public static SqlConnection Connection
{
get { return conn; }
}
public static void ReadyConnection()
{
conn = new SqlConnection();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["DBConnectionString"].ToString();
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
}
public static int ExecuteNonQuery(SqlCommand command)
{
try
{
ReadyConnection();
command.Connection = conn;
int result = command.ExecuteNonQuery();
return result;
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Dispose();
if (conn.State == ConnectionState.Open) conn.Close();
conn.Dispose();
}
}
public static SqlDataReader ExecuteReader(SqlCommand command)
{
try
{
ReadyConnection();
command.Connection = conn;
SqlDataReader result = command.ExecuteReader(CommandBehavior.CloseConnection);
return result;
}
catch (Exception Ex)
{
throw Ex;
}
}
public static object ExecuteScalar(SqlCommand command)
{
try
{
ReadyConnection();
command.Connection = conn;
object value = command.ExecuteScalar();
if (value is DBNull)
{
return default(decimal);
}
else
{
return value;
}
}
catch (Exception ex)
{
throw ex;
}
}
public static void ClearPool()
{
SqlConnection.ClearAllPools();
}
}
PS: does C#'s System.Data.SqlClient use MySQL or SQLite or something else?
MySQL provides their own C# dll for connecting to their database, as do the majority of other database manufacturers. I recommend using theirs. I typically using the built-in SQL client for MS SQL (I am not aware if it can be used with other DBs).
As for this line: insertDefData(myConn) -> the method is not included in your code sample.
As for SQL debugging in general, use the GUI for debugging. I know a lot of people who grew up on MySQL do not want to, or do not understand why you should use one, but it's really a good idea. If you are connecting to MySQL, I recommend MySQL WorkBench CE; if you are connecting to a MS database, SQL Management Studio is what you want. For others, GUIs should be available. The idea here is that you can selectively highlight sections of your query and run it, something not available via command-line. You can have several queries, and only highlight the ones you want to run. Plus, exploring the RDBMS is easier via a GUI.
And if you want to prevent a SQL injection attack, just Base64 encode the string data going in.
As for the connection string itself, we will need some more data on what type of database, exactly, you are trying to connect to. Personally, I recommend just creating a separate SQL account to handle operations (easier to track, and you only need to give it permissions to what you want it to access; security and all that).