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);
}
}
Related
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
The code for the update SQL takes the value from the field in the database and adds it to the number of points in this transaction then is supposed to update the field. Any help on this would be appreciated
string strCon = Properties.Settings.Default.ConString;
OleDbConnection conn = new OleDbConnection(strCon);
conn.Open();//database open
string strSQl = "SELECT points from customer WHERE customerID = " + txtCustID.Text + "";
OleDbCommand cmd = new OleDbCommand(strSQl, conn);
OleDbDataReader reader = cmd.ExecuteReader();//reader open
string strOutput = "";
while (reader.Read())
{
strOutput += reader["points"].ToString();
}//end while loop
int intcurrent = Convert.ToInt32(strOutput);
int intNewTrans = Convert.ToInt32(lblPoints.Text);
int intNewPoints = intcurrent + intNewTrans;
string strSqlUpdate = "UPDATE customer SET points = " + intNewPoints + " WHERE customerID = " + txtCustID.Text + "";
OleDbCommand cmdUpdate = new OleDbCommand(strSqlUpdate, conn);
string strUpdateOutput = "";
while (reader.Read())
{
strUpdateOutput += reader["points"].ToString();
}//end while loop
MessageBox.Show(strUpdateOutput);
reader.Close();
conn.Close();//database closed
Because you are not executing your update command. Just use ExecuteNonQuery like;
cmdUpdate.ExecuteNonQuery();
But more important, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks. Also use using statement to dispose your connection, command and reader automatically instead of calling Close or Dispose methods manually.
I want to write an sql query to a file, but I'm only able to write one column of the query inside the text file. How do I add more columns ?
This is my c# windows form code:
SqlConnection con = new SqlConnection(#"Data Source=" + globalvariables.hosttxt + "," + globalvariables.porttxt + "\\SQLEXPRESS;Database=ha;Persist Security Info=false; UID='" + globalvariables.user + "' ; PWD='" + globalvariables.psw + "'");
SqlCommand command = con.CreateCommand();
command.CommandText = "Select * from bestillinger";
con.Open();
SqlDataReader queryReader = command.ExecuteReader();
while (queryReader.Read())
{
StreamWriter file = new StreamWriter(#"C:\Users\Michael\Desktop\query.txt");
file.WriteLine(queryReader["ordrenr"]);
file.Close();
}
queryReader.Close();
con.Close();
It wont allow me to write:
file.WriteLine(queryReader["ordrenr"] + queryReader["user"]);
I realize this six years old now, but seeing as I came across this in my own searching, I felt that offering a slightly cleaner answer would be good for others, as well. Also, I can't make comments yet, so I thought I might as well submit this as an answer.
The OP's answer presents a pretty major performance issue with recreating the stream with every row, as pointed out by Magus in the comments.
Meanwhile, mybirthname's answer actually never ends up adding a header row, and if the bool included is changed to true upon creation, it'll end up making a file filled with nothing but headers.
In this particular case, I'm writing the data out in a Comma Separated Value format. The file extension can be .csv if you want to open this in a spreadsheet editor afterwards, or .txt if it's not meant to be viewed by any end user.
//Consider putting your connection string in a config file and referencing it here.
SqlConnection sqlConn = new SqlConnection(Properties.Settings.Default.ConnString);
//If possible, avoid using "Select *" and instead, select only the columns you care about to increase efficiency.
SqlCommand sqlCmd = new SqlCommand("Select ordrenr, user From bestillinger", sqlConn);
sqlConn.Open();
SqlDataReader sdr = sqlCmd.ExecuteReader();
if (sdr.HasRows)
{
//There's really no reason to create the StreamWriter unless you actually find some data.
StreamWriter swExportWriter = new StreamWriter(#"C:\DataStore\Datafile.csv");
//Now that you know you have data, go ahead and write the first line to the file as the header row.
swExportWriter.WriteLine("ordrenr, user");
//Now use SqlDataReader.Read() to loop through the records and write each one to the file.
while (sdr.Read())
{
swExportWriter.WriteLine("{0},{1}", sdr["ordrenr"], sdr["user"]);
}
//Don't forget to close the StreamWriter!
swExportWriter.Close();
}
sdr.Close();
sqlConn.Close();
If you'd like to use Using statements instead, as per Magus' suggestion (which is probably a good idea), you can also structure it like so:
using (SqlConnection sqlConn = new SqlConnection(Properties.Settings.Default.ConnString))
{
SqlCommand sqlCmd = new SqlCommand("Select ordrenr, user From bestillinger", sqlConn)
sqlConn.Open();
using (SqlDataReader sdr = sqlCmd.ExecuteReader())
{
if (sdr.HasRows)
{
using (StreamWriter swExportWriter = new StreamWriter(#"C:\DataStore\Datafile.csv"))
{
swExportWriter.WriteLine("ordrenr, user");
while (sdr.Read())
{
swExportWriter.WriteLine("{0},{1}", sdr["ordrenr"], sdr["user"]);
}
}
}
}
}
I found a way:
file.WriteLine("{0},{1}", queryReader["ordrenr"], queryReader["user"]);
static void Main(string[] args)
{
string connString = #"here connection string";
SqlConnection con = new SqlConnection(connString);
SqlCommand command = con.CreateCommand();
command.CommandText = "Select * from Object";
con.Open();
SqlDataReader queryReader = command.ExecuteReader();
StreamWriter file = new StreamWriter(#"C:\Projects\EverydayProject\test.txt");
bool addColumns = false;
string columnName1="Title";
string columnName2 = "City";
while (queryReader.Read())
{
if(addColumns)
{
file.WriteLine(columnName1 + " " + columnName2);
addColumns = true;
}
else
{
file.WriteLine(queryReader["Title"].ToString() + " " + queryReader["City"].ToString());
}
}
queryReader.Close();
con.Close();
file.Close();
}
This is working you should first make the objects to String() also you need to close the file at the end. Not on first iteration !
I currently have a little app sends a lot of different MySQL Queries to the server. My idea was to wrap the connection, the query and the read to a function with only the actual query as a parameter.
Here is what I got:
public static MySqlDataReader mySqlRead(string cmdText)
{
string connString = "server=" + ORVars.sqlServerAddr + ";port=" + ORVars.sqlServerPort + ";uid=" + ORVars.sqlServerUID + ";pwd=" + ORVars.sqlServerPass + ";database=" + ORVars.sqlServerDB + ";";
MySqlConnection conn = new MySqlConnection(connString);
MySqlCommand command = conn.CreateCommand();
command.CommandText = cmdText;
try
{
conn.Open();
MySqlDataReader reader = command.ExecuteReader();
return reader;
}
catch (MySqlException)
{
throw;
}
}
I connect and send the query here:
private void btnLogin_Click(object sender, EventArgs e)
{
string username = txtLogin.Text;
string password = ORFunc.GetMD5Hash(txtPassword.Text);
MySqlDataReader orRead = ORFunc.mySqlRead("SELECT * FROM orUsers WHERE username = '" + username + "' AND pass = '" + password + "'");
while (orRead.Read())
{
MessageBox.Show(orRead["id"].ToString());
}
}
Works like a charm... BUT, as you can see above, the connection is never closed. When I add the conn.Close() behind the .ExecuteReader() the reader is empty and everything after return is of course useless.
Maybe it's a stupid question but I'm rather new to C# so please be generous, any hint is appreciated.
cheers,
PrimuS
I had a similar problem in JAVA recently, but I think the same will work for you. Essentially, you can create a class that represents a "SqlCall" object (or something). The class would have accessible members including the connection and the results. The ctor for the class would take in your query text.
Then, all you would have to do is create a new instance of that class, run the query in a method in that class (which would set and/or return the results), GET the results, and then when you are done, call close() on your class (which would then have to be coded such that it closes the connection held internally).
Technically, a better way to do this is to EXTEND the connection class itself, but as you are new to C#, I will not go into the details of doing so.
As I was writing the code below, I realized I may have not actually answered your question. But there's no point in backing out now, so here's what I have:
public class SqlCall {
private static connString = "server=" + ORVars.sqlServerAddr + ";port=" + ORVars.sqlServerPort + ";uid=" + ORVars.sqlServerUID + ";pwd=" + ORVars.sqlServerPass + ";database=" + ORVars.sqlServerDB + ";";
private MySqlConnection conn;
private MySqlCommand command;
private MySqlDataReader reader;
public SqlCall(String query) {
conn = new MySqlConnection(connString);
command = conn.CreateCommand();
command.CommandText = query;
}
public MySqlDataReader execute() throws Exception {
conn.Open();
reader = command.ExecuteReader();
return reader;
}
public void close() {
reader.close();
conn.close();
}
}
Your login code would be:
private void btnLogin_Click(object sender, EventArgs e) {
string username = txtLogin.Text;
string password = ORFunc.GetMD5Hash(txtPassword.Text);
SqlCall sqlcall = new SqlCall("SELECT * FROM orUsers WHERE username = '" + username + "' AND pass = '" + password + "'");
try {
MySqlDataReader orRead = sqlcall.execute();
while (orRead.Read())
{
MessageBox.Show(orRead["id"].ToString());
}
sqlcall.close();
} catch (Exception ex) {
// dostuff
}
}
The point is, unless you copy the data into a new datatable at the very beginning, you'll have to keep the connection open.
On a separate note, YOUR CODE IS PRONE TO SQL INJECTION. Don't know what that is? An example: if I said my username was ';DROP TABLE orUsers;--, then your entire user database would be gone. Look into stored procedures if you want a (very healthy) way around this.
You have difficulties because your idea works against the pattern expected by programs that connects to a database in NET Framework.
Usually, in this pattern you have a method that
INITIALIZE/OPEN/USE/CLOSE/DESTROY
the ADO.NET objects connected to the work required to extract or update data
Also your code has a serious problem called Sql Injection (see this famous explanation) because when you concatenate strings to form your command text you have no defense against a malicious user that try to attack your database
private void btnLogin_Click(object sender, EventArgs e)
{
string username = txtLogin.Text;
string password = ORFunc.GetMD5Hash(txtPassword.Text);
MySqlParameter p1 = new MySqlParameter("#uname", username);
MySqlParameter p2 = new MySqlParameter("#pass", pass);
string cmdText = "SELECT * FROM orUsers WHERE username = #uname AND pass = #pass"
DataTable dt = ORFunc.GetTable(cmdText, p1, p2);
foreach(DataRow r in dt.Rows)
{
Console.WriteLine(r["ID"].ToString());
}
}
public static DataTable GetTable(string cmdText, params MySqlParameter[] prms)
{
string connString = "server=" + ORVars.sqlServerAddr + ";port=" + ORVars.sqlServerPort + ";uid=" + ORVars.sqlServerUID + ";pwd=" + ORVars.sqlServerPass + ";database=" + ORVars.sqlServerDB + ";";
// This is the INITIALIZE part
using(MySqlConnection conn = new MySqlConnection(connString))
using(MySqlCommand command = new MySqlCommand(cmdText, conn))
{
// OPEN
conn.Open();
DataTable dt = new DataTable();
command.Parameters.AddRange(prms);
// USE
MySqlDataReader reader = command.ExecuteReader();
dt.Load(reader);
return dt;
} // The closing brace of the using statement is the CLOSE/DESTROY part of the pattern
}
Of course this is a generic example and in my real work I don't use very often these generic methods and prefer to write specialized data access code that return the base object needed to the upper layer of code
i have a webservice and a comsumer, the webservice has its methode where it returns data from a mysql database.
in the comsumer i called
WebService.Service1 Service = new WebService.Service1();
in the beginning (not within a methode)
when the consumer starts asking for data it will be 20 requests within 10 minutes first 15-18 requests worked perfectly but the last few times it returns the error
Server was unable to process request. ---> The connection is already
open.
I hope i provided enough information like this, i rather not post the code.
This is the methode of the webservice:
public string GetAnswer(string Question, string Option1, string Option2, string Option3, string Option4)
{
string connstring = "Server=Server;Port=3306;Database=DB;UID=User;password=pw;";
MySqlConnection conn = new MySqlConnection(connstring);
MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT * FROM `tbl` where `Question` = '" + Question + "' LIMIT 1";
conn.Open();
MySqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
string TheAnswer = "";
while (reader.Read())
{
string question = reader["Question"].ToString();
string answer = reader["Answer"].ToString();
if (Option1.Equals(answer))
TheAnswer = Option1;
if (Option2.Equals(answer))
TheAnswer = Option2;
if (Option3.Equals(answer))
TheAnswer = Option3;
if (Option4.Equals(answer))
TheAnswer = Option4;
}
conn.Close();
conn.Dispose();
return TheAnswer;
}
else
{
MySqlCommand command2 = conn.CreateCommand();
command.CommandText = "Insert Into `new` (`Question`, `Answer1`,`Answer2`,`Answer3`,`Answer4`) VALUES ('" + Question + "','" + Option1 + "','" + Option2 + "','" + Option3 + "', '" + Option4.Replace("~", " ") + "')";
conn.Open();
command.ExecuteNonQuery();
conn.Close();
conn.Dispose();
return "Error: Question is unknown, saving the question to get it answered.";
}
}
You have conn.open() in your else statement, and the connection was already opened before that. You should probably consider using the using statement:
using (MySqlConnection conn = new MySqlConnection(connstring))
{
using (MySqlCommand command2 = conn.CreateCommand())
{
}
}