Socket c# send data to SQLite Database, Database is closed - c#

I have two apps with multiple Databases, a simple explanation is:
Main App: get the info from a database(firebase or SQLServer) and send by client socket to the second app.
Display App: get the socket info and insert into SQLite database, after shows the data in a WinForm.
My problem is sometimes Sqlite has an error doing the insert (Database is locked), because i need many inserts in a little time. I'm working in a payout machine and if the machine get 0,5€ have to send to the display quickly.
I use MDSN Server, and this modified code:
if (content.IndexOf("<EOF>") > -1)
{
//This is amount to pay
string searchString = "<EOF>";
int endIndex = content.IndexOf(searchString);
s = content.Substring(0, endIndex);
string insertar = "INSERT INTO transacciones " +
"VALUES ('" + DateTime.Today + "','" + s + "',NULL);";
//Insert
SQLite bd = new SQLite();
bd.Insert(insertar);
Send(handler, content);
}
else if (content.IndexOf("<REC>") > -1)
{
//This is the pay
SQLite bd = new SQLite();
string searchString = "<REC>";
int endIndex = content.IndexOf(searchString);
s = content.Substring(0, endIndex);
int id = bd.GetId();
string insertar = "UPDATE transacciones " +
"SET cobrado= '" + s + "' WHERE ROWID=" + id + ";";
//Update
bd.Insert(insertar); //here i have the problem
Send(handler, content);
}
when I insert in the pay machine a lot of coins my display app begins to go slow and near the sixth update (sometimes more or less) i get the error:
SQLite error (5): database is locked
The function insert is:
public Boolean Insert(string sql)
{
try
{
SQLiteConnection con = new SQLiteConnection("data source=" + Datos.dataBase + "\\bdDisplay.sqlite;Version=3;New=False;Compress=True;");
con.Open();
SQLiteCommand command = new SQLiteCommand(sql, con);
command.ExecuteNonQuery();
command.Dispose();
con.Close();
return true;
}
catch (SQLiteException ex)
{
MessageBox.Show("Error Insert: " + ex.Message);
return false;
}
}
Maybe the error comes from do not parametricer?
Or comes from too many operations? in this case, can i do something to debug?

Yes, it is better to use using(){} or else you need to use
try{
} catch(){
}
finally{
//to dispose
}
and it will improve performance if you use UnitOfWork style, like on your update part may be better to Unite it such:
//This is the pay
SQLite bd = new SQLite();
string searchString = "<REC>";
int endIndex = content.IndexOf(searchString);
s = content.Substring(0, endIndex);
bd.Update(s);
....
public bool Update(object value)
{
using (var conn = new SQLiteConnection(...))
{
conn.Open();
// GetId().
//reconstruct sql command then
//do insert
}
// this way only use single conn for both getId and Insert
}

you don't dispose when the error is received.
using (SQLiteConnection c =
new SQLiteConnection("data source=" + Datos.dataBase +
"\\bdDisplay.sqlite;Version=3;New=False;Compress=True;"))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
var effect = cmd.ExecuteNonQuery();
return effect > 0;
}
}
for you is big problem. maybe you need only finaly area.how to use finaly area

Related

Conversion failed when converting from a character string to uniqueidentifier when inserting value to sql

I have simple SQL table called test which has two column.first column is an TINYINT and second one is a type of UNIQUEIDENTIFIER.
I have created simple method to insert values into "test" table using for loop and its working fine without any errors.But once i try to create string to uniqueidentifier conversion error it will roll back the transaction and delete all previous inserted values in same transaction.
This is the place where conversion happen
strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";
Here is the my complete code
private static string TryThisPlease()
{
SqlConnection connection = null;
SqlCommand command = null;
SqlTransaction transaction = null;
string strRet = "OK";
try
{
connection = new SqlConnection(connectionString);
connection.Open();
//starting transaction mode
transaction = connection.BeginTransaction(IsolationLevel.Snapshot);
command = new SqlCommand("Test", connection);
command.CommandType = CommandType.Text;
command.Transaction = transaction;
//for (int i = 255; i < 257; i++)
for (int i = 250; i < 255; i++)
{
string[] strData = new string[] { "", "3" };
string strCommand = "";
//strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + Guid.NewGuid().ToString() + "'); ";
strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";
command.CommandText = strCommand;
if (command.Connection.State != ConnectionState.Open)
command.Connection.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception EX)
{
strRet = "FAIL";
try
{
}
catch (Exception)
{
strRet = "FAIL";
}
}
}
transaction.Commit();
}
catch (Exception EX)
{
transaction.Rollback();
strRet = "FAIL";
}
finally
{
connection.Close();
}
return strRet;
}
Uncommenting the two lines commented and commenting out lines below,another error with same severity happens. Transactions are not rolled back in this scenario
Is there any way to prevent the transaction being rollback or did i miss something in my code ?
if you want previous inserts to be successful, what you have to do is, create and commit the transaction inside the foreach loop, so that each row is considered separate transaction.
using(SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
for (int i = 250; i < 255; i++) {
using(SqlCommand command = new SqlCommand("", connection, trans)) {
command.CommandType = System.Data.CommandType.Text;
using(SqlTransaction trans = connection.BeginTransaction()) {
try {
strCommand = "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";
command.CommandText = strCommand;
command.ExecuteNonQuery();
trans.Commit();
}
catch(Exception e) {
//Handle Error
trans.Rollback();
}
}
}
}
}
But, your command is prone for sql injection attacks. I would suggest you to parametrize the query as given below:
SqlCommand cmd = new SqlCommand(
"INSERT INTO Test(Test, Test2) VALUES(#id1,#id2)", conn);
cmd.Parameters.Add( new SqlParameter(#id1, SqlDbType.Int)).Value = i;
cmd.Parameters.Add( new SqlParameter(#id2, SqlDbType.Guid)).Value = (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString());
UPDATE
If you want to still go with batch transaction, you can consider savepoint for the transaction. Instead of rolling back the whole transaction, you can rollback till the savepoint.Read more on Savepoint
command.CommandText = strCommand;
trans.Save($"save{i}");
command.ExecuteNonQuery();
trans.Commit();
}
catch(Exception e) {
//Handle Error
trans.Rollback($"save{i}");
trans.Commit();
}
The problem lies in this statement Guid.NewGuid().ToString().Remove(12, 1). The result of this statement will remove the 12th character from your generated GUID which is not a valid GUID and hence the database insertion fails.
Guid Format:
"00000000-0000-0000-0000-000000000000"
^ 12th index character which will get removed from the Guid.
When the condition i==251 becomes true this code Guid.NewGuid().ToString().Remove(12, 1) will get executed and it will generate the error. You need to update this to produce GUID in correct format inorder to solve your issue.

Can't get process to stop reading data during sleep

I am having a problem with my C# code. The code is designed to read RFID tags and based on the UID, tell a database what kind of process to start. The problem I am having is when I read a tag and set it to the required sleep, it stil reads tags and basically waits with executing the next procedure with the UID it wasn't even supposed to read.
Code:
string myConnectionString = "server=" + mysql_host + ";uid=" + mysql_user + ";" + "pwd=" + mysql_pass + ";database=" + mysql_daba;
MySqlConnection connect;
connect = new MySqlConnection(myConnectionString);
string query = "SELECT * FROM Tags WHERE tagCode = #tagCode";
AutodetectArduinoPort();
try{
ArduPort.PortName = AutodetectArduinoPort();
ArduPort.Open();
ArduPort.Write("startmonitor");
}
catch{
Console.WriteLine("comport did not connect.");
}
int delay;
while (true){
string tagData = ArduPort.ReadLine();
Console.WriteLine(tagData);
connect.Open();
MySqlCommand command = new MySqlCommand(query, connect);
command.Parameters.AddWithValue("#tagCode", tagData);
MySqlDataReader reader = command.ExecuteReader();
if (reader.Read()){
string url = reader.GetValue(3).ToString();
delay = Convert.ToInt32(reader.GetValue(4));
command.Dispose();
Process.Start(url);
connect.Close();
Thread.Sleep(delay);
}
}
Provided I understood you correctly:
string tagData = ArduPort.ReadLine();
Covers a separate library. Called "ArduPort".
ArduPort is not effected by your "Thread.Sleep(delay);" Function.
You will have to modify the ArduPort code to implement a delay between reads, if you want to pause it's reading ability.
Whatever was picked up on the port, will simply be stored until your readline, fires again after a wait.
You need to change the scan code itself, to pause reading scans for your delay if this is what you want.
If I didn't understand you correctly, please provide:
1, a clear input example in your question.
2, a clear expected result in your question.
3, a set of possible constraints.
The more details you can give, the better we can tailor our answers to your question.
EDIT: My Answer still applies to a serial port component.
this ended up being the solution thanks to KMoussa.
I`m now closing the arduport as soon as the UID is saved to a string. and opening it when the loop restarts basically.
string myConnectionString = "server=" + mysql_host + ";uid=" + mysql_user + ";" + "pwd=" + mysql_pass + ";database=" + mysql_daba;
MySqlConnection connect;
connect = new MySqlConnection(myConnectionString);
string query = "SELECT * FROM Tags WHERE tagCode = #tagCode";
AutodetectArduinoPort();
while (true){
try
{
ArduPort.PortName = AutodetectArduinoPort();
ArduPort.Open();
ArduPort.Write("startmonitor");
}
catch
{
Console.WriteLine("comport did not connect.");
}
int delay;
string tagData = ArduPort.ReadLine();
ArduPort.Close();
Console.WriteLine(tagData);
connect.Open();
MySqlCommand command = new MySqlCommand(query, connect);
command.Parameters.AddWithValue("#tagCode", tagData);
MySqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
string url = reader.GetValue(3).ToString();
delay = Convert.ToInt32(reader.GetValue(4));
command.Dispose();
Process.Start(url);
connect.Close();
Thread.Sleep(delay);
}
}

IErrorInfo.GetDescription failed with E_FAIL(0x80004005) using Windows Search API via OleDB

I'm using the Windows Search API from C# (OleDB access) to retrieve all the index entries on a local machine (Windows 8.1) search index using the following C# code:
string query = #"SELECT System.ItemNameDisplay,SYSTEM.ITEMURL,System.DateModified, System.ItemName, System.Search.AutoSummary,System.Search.GatherTime FROM SystemIndex";
query = query + "WHERE System.Search.GatherTime > '" + LastRunTime.ToString("yyyy-MM-dd h:mm:ss") + "' Order by System.Search.GatherTime Desc";
string connectionString = "Provider=Search.CollatorDSO;ExtendedProperties=\"Application=Windows\"";
OleDbConnection connection = new OleDbConnection(connectionString);
connection.Open();
OleDbCommand command;
command = new OleDbCommand(query, connection);
Cursor.Current = Cursors.WaitCursor;
reader = command.ExecuteReader();
int iResults = 0;
int iSummaries = 0;
string sDate = "";
string sText = "";
string sFile = "";
while (reader.Read())
{
try
{
sText = reader.GetValue(4).ToString();
sFile = reader.GetString(1);
sDate = reader.GetDateTime(5).ToString();
Debug.Print(iResults + " " + sFile + " " + sDate);
//if (sText != "") { Debug.Print(sText); iSummaries++; }
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
iResults++;
}
I find that that the code crashes non-reproducibly on the While(Reader.Read()) line with the error IErrorInfo.GetDescription failed with E_FAIL(0x80004005). The loop processes about 55,000 of the 76,080 entries. If I comment out sText = reader.GetValue(4).ToString(); then the loop runs much faster, as the Autosummary field is about 1000 characters and is present for most of the entries. No crash occurs in this case . If I set a breakpoint in the loop and step through one entry at a time, the crash occurs much sooner, making me think that it is a timing problem. Has anyone had similar problems with programmatic access to search indexes and found a workaround?
Set CommandTimeout to 0 after defining the OLEdb command with the query and this seems to have fixed the problem.

How to create new database upon reopening application?

I have a log viewing application that writes log statements to a database and then sends them from the database to the log viewer GUI. I want to be able to open more than one instance of the log viewer but when I do it will be creating a database with the same name as the previous instance of the viewer. I've tried creating a database with a different name if one has already been created but that doesn't seem to work. Any suggestions? Here's the code for creating/accessing/destroying databases:
public class Database
{
public bool hasAdminPriv
{
get;
set;
}
public bool hasBeenCreated
{
get;
set;
}
public Database()
{
hasAdminPriv = true;
//Construction checks to see if user has Admin priveleges
bool isElevated;
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
isElevated = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (!isElevated)
hasAdminPriv = false;
}
//returns true if the database creation was successful
public bool CreateDatabase()//creates a database dynamically by making a query request to the server
{
String str;
SqlConnection myConn = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS; Initial Catalog=Master;Integrated Security=True");
str = "CREATE DATABASE MyDatabase ON PRIMARY " +
"(NAME = MyDatabase_Data, " +
"FILENAME = 'C:\\Program Files (x86)\\Microsoft SQL Server\\MSSQL.1\\MSSQL\\Data\\MyDatabaseData.mdf', " +
"SIZE = 30MB, MAXSIZE = 10GB, FILEGROWTH = 20%) " +
"LOG ON (NAME = MyDatabase_Log, " +
"FILENAME = 'C:\\Program Files (x86)\\Microsoft SQL Server\\MSSQL.1\\MSSQL\\Data\\MyDatabaseLog.ldf', " +
"SIZE = 10MB, " +
"MAXSIZE = 1GB, " +
"FILEGROWTH = 10%)";
SqlCommand myCommand = new SqlCommand(str, myConn);
try
{
myConn.Open();
myCommand.ExecuteNonQuery();
}
catch (System.Exception ex)
{
int done = 0;
while (done < 10)
{
String str2 = "CREATE DATABASE" + done + " MyDatabase ON PRIMARY " +
"(NAME = MyDatabase_Data, " +
"FILENAME = 'C:\\Program Files (x86)\\Microsoft SQL Server\\MSSQL.1\\MSSQL\\Data\\MyDatabaseData.mdf', " +
"SIZE = 30MB, MAXSIZE = 10GB, FILEGROWTH = 20%) " +
"LOG ON (NAME = MyDatabase_Log, " +
"FILENAME = 'C:\\Program Files (x86)\\Microsoft SQL Server\\MSSQL.1\\MSSQL\\Data\\MyDatabaseLog.ldf', " +
"SIZE = 10MB, " +
"MAXSIZE = 1GB, " +
"FILEGROWTH = 10%)";
SqlCommand myCommand2 = new SqlCommand(str2, myConn);
try{
myCommand2.ExecuteNonQuery();
}
catch{
++done;
}
myConn.Close();
hasBeenCreated = true;
return true;
}
return false;
}
finally
{
if (myConn.State == ConnectionState.Open)
{
myConn.Close();
}
}
hasBeenCreated = true;
return true;
}
//Creates the table in the database by a query request
//a return value of true means Database was created succesfully
public bool CreateTable()
{
SqlConnection myConn = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS; Initial Catalog=MyDatabase;Integrated Security=True");
string createString = "CREATE TABLE storage (ID INT NOT NULL, Level varchar(255) , LevelInt INT, DateTime varchar(255),Counter smallint,Device varchar(255), Source varchar(255), Description varchar(255),PRIMARY KEY (ID))"; //YOUR SQL COMMAND TO CREATE A TABLE
SqlCommand create = new SqlCommand(createString, myConn);
myConn.Open();
create.ExecuteNonQuery();
myConn.Close();
return true;
}
//Add the element's values to the database/table to later recall/reorder
public bool addElement(LogParse log,int num)
{
SqlConnection con = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True");
try
{
con.Open();
SqlCommand cmd = new SqlCommand("Insert into storage(ID, Level, LevelInt, DateTime, Counter, Device, Source, Description) values(" + num + ",#Level, #LevelInt, #DataTimeItem,#counterItem,#deviceItem,#sourceItem,#descItem)", con);
cmd.Parameters.AddWithValue("#Level", log.Level);
cmd.Parameters.AddWithValue("#LevelInt", log.LevelInt);
cmd.Parameters.AddWithValue("#DataTimeItem", log.TimeStamp);
cmd.Parameters.AddWithValue("#counterItem", log.SequentialNumber);
cmd.Parameters.AddWithValue("#deviceItem", log.Device);
cmd.Parameters.AddWithValue("#sourceItem", log.Source);
cmd.Parameters.AddWithValue("#descItem", log.Description);
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception ee)
{
return false;
}
return true;
}
//outputs a string array with all the values in the database
public LogParse[] readValue(int start, int end)
{
SqlConnection con = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True");
con.Open();
LogParse[] s = new LogParse[end - start];
try
{
using (var oCommand = new SqlCommand("SELECT * From storage WHERE ID BETWEEN #Start AND #End", con))
{
oCommand.Parameters.AddWithValue("#Start", start);
oCommand.Parameters.AddWithValue("#End", end);
using (var oReader = oCommand.ExecuteReader())
{
int i = 0;
while (oReader.Read() && i < end-start)
{
//s[i] = oReader.GetString(1) + oReader.GetString(2) + oReader.GetString(3);
String Level = oReader.GetString(1);
Int32 LevelInt = oReader.GetInt32(2);
String Datetime = oReader.GetString(3);
Int16 SequentialNumber = (Int16)oReader.GetValue(4);
String Device = oReader.GetString(5);
String Source = oReader.GetString(6);
String Description = oReader.GetString(7);
s[i] = new LogParse();
s[i].Level = Level;
s[i].LevelInt = LevelInt;
s[i].TimeStamp = DateTime.Parse(Datetime);
s[i].SequentialNumber = SequentialNumber;
s[i].Device = Device;
s[i].Description = Description;
s[i].Source = Source;
++i;
}
}
}
}
catch
{
}
con.Close();
return s;
}
//Deletes the database by a query statement
//a return value of true means the delete was succesful
public static bool deleteDatabase()
{
String str;
SqlConnection myConn = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS; Initial Catalog=Master;Integrated Security=True");
str = #"ALTER DATABASE MyDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE;DROP DATABASE [MyDatabase]";
SqlCommand myCommand = new SqlCommand(str, myConn);
try
{
myConn.Open();
myCommand.ExecuteNonQuery();
}
catch (System.Exception ex)
{
return false;
}
finally
{
if (myConn.State == ConnectionState.Open)
{
myConn.Close();
}
}
return true;
}
}
DON'T create another database, or table, it's evil. Just add Instance ID into table storage. And when writing new logs just add instance ID, same goes when reading from DB, put instance ID into where clause.
Another issue is to pick good Instance ID, your scenario is not very clear to me, but if you want every new application instance to have separate data, just create new GUID and use it as Instance ID.
For example you can have static property InstanceID in your Database class, and your class could look something like this :
public class Database
{
public static Guid InstanceID = new Guid();
//Add the element's values to the database/table to later recall/reorder
public bool addElement(LogParse log,int num)
{
SqlConnection con = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True");
try
{
con.Open();
SqlCommand cmd = new SqlCommand("Insert into storage(ID, InstanceID, Level, LevelInt, DateTime, Counter, Device, Source, Description) values(" + num + ",#Level, #LevelInt, #DataTimeItem,#counterItem,#deviceItem,#sourceItem,#descItem)", con);
// writing InstanceID
cmd.Parameters.AddWithValue("#InstanceID", Database.InstanceID);
cmd.Parameters.AddWithValue("#Level", log.Level);
cmd.Parameters.AddWithValue("#LevelInt", log.LevelInt);
cmd.Parameters.AddWithValue("#DataTimeItem", log.TimeStamp);
cmd.Parameters.AddWithValue("#counterItem", log.SequentialNumber);
cmd.Parameters.AddWithValue("#deviceItem", log.Device);
cmd.Parameters.AddWithValue("#sourceItem", log.Source);
cmd.Parameters.AddWithValue("#descItem", log.Description);
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception ee)
{
return false;
}
return true;
}
//outputs a string array with all the values in the database
public LogParse[] readValue(int start, int end)
{
SqlConnection con = new SqlConnection("Data Source=" + Environment.UserName + "-D1SD\\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True");
con.Open();
LogParse[] s = new LogParse[end - start];
try
{
// select with InstanceID
using (var oCommand = new SqlCommand("SELECT * From storage WHERE InstanceID = #InsID ID BETWEEN #Start AND #End", con))
{
oCommand.Parameters.AddWithValue("#Start", start);
oCommand.Parameters.AddWithValue("#End", end);
oCommand.Parameters.AddWithValue("#InsID", Database.InstanceID);
using (var oReader = oCommand.ExecuteReader())
{
int i = 0;
while (oReader.Read() && i < end-start)
{
//s[i] = oReader.GetString(1) + oReader.GetString(2) + oReader.GetString(3);
String Level = oReader.GetString(1);
Int32 LevelInt = oReader.GetInt32(2);
String Datetime = oReader.GetString(3);
Int16 SequentialNumber = (Int16)oReader.GetValue(4);
String Device = oReader.GetString(5);
String Source = oReader.GetString(6);
String Description = oReader.GetString(7);
s[i] = new LogParse();
s[i].Level = Level;
s[i].LevelInt = LevelInt;
s[i].TimeStamp = DateTime.Parse(Datetime);
s[i].SequentialNumber = SequentialNumber;
s[i].Device = Device;
s[i].Description = Description;
s[i].Source = Source;
++i;
}
}
}
}
catch
{
}
con.Close();
return s;
}
}
btw. DON'T swallow exceptions ! I leave your code the same but please don't do that, it's also evil, another thing is if there is a exception in your addElement method your connection will not be closed, use Using statement.
that doesn't sound safe at all, maybe one database with several user tables to store the logfiles for each user, but this just doesn't sound right to me.
otherwise a variable that is assigned randomly when the application is started in place of the database name when it is created.
but if you do something wrong there are going to be a lot of databases out there, but it looks like you have figured out sizing and some other things to keep them from overpowering the server machine.
Additional Information from Comment
if you are going to use tables on the Database(which I think is what you really need) then create the database separate and then create randomly named tables inside your application every time it is opened, you may want to have another table that would keep track of the the tables and the times they were opened as well, perhaps even what user opened them and such things like that

Code to create & connect to a SQL Server database: Whats wrong with it?

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).

Categories