I have a code in which I am trying to insert the records. All the records are inserted but with duplicates. I want to stop duplication of same record.
public int SaveReadingsInCIS(Reading pReading)
{
SqlConnection con = new SqlConnection("Data Source=RND-FAISAL;Initial Catalog=hesco;Integrated Security=True;MultipleActiveResultSets=True;");
int result = -1;
string dt = pReading.XTimeStamp.Replace("T"," ");
string fdt = dt.Remove(dt.Length-6);
if (con.State != ConnectionState.Open)
{
con.Open();
}
SqlCommand insert_cmd = new SqlCommand("INSERT INTO [dbo].[billing]([unique_id],[ref_no],[msn],"+
"[kWh1],[kVarh1],[kWh2],[kVarh2],[datetime])VALUES(#uniqueid,#refno,#msn,#kwh1,#kvarh1,#kwh2,#kvarh2,#datetime)",con);
insert_cmd.CommandType = CommandType.Text;
insert_cmd.Parameters.AddWithValue("#uniqueid",pReading.App_no);
insert_cmd.Parameters.AddWithValue("#refno",pReading.Ref_no);
insert_cmd.Parameters.AddWithValue("#msn",pReading.Serial_no);
insert_cmd.Parameters.AddWithValue("#kwh1",pReading.KWH1);
insert_cmd.Parameters.AddWithValue("#kvarh1",pReading.KVARH1);
insert_cmd.Parameters.AddWithValue("#kwh2",pReading.KWH2);
insert_cmd.Parameters.AddWithValue("#kvarh2",pReading.KVARH2);
insert_cmd.Parameters.AddWithValue("#datetime", fdt.ToString());
try
{
result = insert_cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
result = ex.HResult;
}
finally
{
if (con != null && con.State == ConnectionState.Open)
{
con.Close();
}
}
return result;
}
In above code there is a date time fdt. There may be duplicate msn but of different date time. I want to stop duplicate insertion of same date time and msn
Any help would be highly appreciated
Related
Is it possible to use SQL command for login and update at the same time? I mean when the Login is done, I want to change logat in 1. Do I have to create a new if with OpenConnection()?
public bool IsLogin(string user, string pass) {
string query = $"SELECT * from utiliz WHERE username='{user}' AND password='{GetSha1(pass)}'";
string query_update = $"UPDATE utiliz SET logat='{1}' WHERE username='{user}'";
try
{
if (OpenConnection())
{
MySqlCommand cmd = new MySqlCommand(query, conn);
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
reader.Close();
conn.Close();
return true;
}
else
{
reader.Close();
conn.Close();
return false;
}
}
else {
conn.Close();
return false;
}
}
catch (Exception ex) {
conn.Close();
return false;
}
}
EDITED
Guys, I have edited my code, following parameters procedure. Is it good what I did?
if (String.IsNullOrEmpty(textBox_pass_login.Text) && String.IsNullOrEmpty(textBox_usr_login.Text) || String.IsNullOrEmpty(textBox_usr_login.Text) || String.IsNullOrEmpty(textBox_pass_login.Text))
{
System.Windows.Forms.MessageBox.Show("Both fields (username,password) are required");
}
else
{
string user = textBox_usr_login.Text;
string password = textBox_pass_login.Text;
string encryptedpass = GetSha1(password);
try
{
using (var connection = conn)
{
string query = "SELECT * from utiliz WHERE username=#user AND password=#password";
using (var command = new MySqlCommand(query, conn))
{
command.Parameters.AddWithValue("#user", user);
command.Parameters.AddWithValue("#password", encryptedpass);
MySqlDataAdapter sda = new MySqlDataAdapter(command);
DataTable dt = new DataTable();
sda.Fill(dt);
conn.Open();
int i = command.ExecuteNonQuery();
conn.Close();
if (dt.Rows.Count > 0)
{
this.Hide();
var form2 = new Form1();
form2.Closed += (s, args) => this.Close();
form2.Show();
}
else
{
System.Windows.Forms.MessageBox.Show("Wrong credentials");
textBox_usr_login.Clear();
textBox_pass_login.Clear();
}
}
}
}
catch
{
System.Windows.Forms.MessageBox.Show("Wrong credentials");
textBox_usr_login.Clear();
textBox_pass_login.Clear();
}
}
There are some important points here. You must use Parameterized queries to improve the performence of your query on the database layer and avoid some problems such as sql injection. You also could use transactions to keep data integrity.
Check the sample bellow with comments (I didn't test this code, may not work properly on your environment):
public bool IsLogin(string user, string pass)
{
// prepare the queries with parameters with '#' and parameter name
const string query = "SELECT count(username) from utiliz WHERE username = #username AND password = #password";
const string query_update = "UPDATE utiliz SET logat = #logat WHERE username = #username";
// prepare the encrypted password
string encryptedPass = GetSha1(pass);
// use a result variable to use as the function result
bool result = false;
try
{
if (OpenConnection())
{
// start a transaction from the connection object
using (MySqlTransaction tran = conn.BeginTransaction())
{
try
{
int userFound = 0;
// prepare the MySqlCommand to use the query, connection and transaction.
using (MySqlCommand userCommand = new MySqlCommand(query, conn, tran))
{
userCommand.Parameters.AddWithValue("#username", user);
userCommand.Parameters.AddWithValue("#password", encryptedPass);
userFound = (int) userCommand.ExecuteScalar();
}
if (userFound > 0)
{
// prepare the MySqlCommand to use the query, connection and transaction to update data
using (MySqlCommand logatCommand = new MySqlCommand(query_update, conn, tran))
{
logatCommand.Parameters.AddWithValue("#logat", DateTime.Now);
logatCommand.Parameters.AddWithValue("#username", user);
logatCommand.ExecuteNonQuery();
}
}
// commit the transaction
tran.Commit();
result = true;
}
catch (Exception ex)
{
// perform some log with ex object.
tran.Rollback();
}
finally
{
conn.Close();
}
}
}
}
catch (Exception e)
{
// perform some log...
return false;
}
return result;
}
As recommended (and demonstrated) by Felipe Oriani, you should use parameterized queries.
Let me pinpoint, however, that you can do this with a single update query. The trick is to filter the update query on both user name and password:
UPDATE utiliz SET logat = #logat WHERE username = #username AND password = #password
You want to run the query with method ExecuteNonQuery, which returns the number of rows affected.
If credentials are valid, the where cause selects the relevant record and the update happens, returning 1 as the count of records affected. Else, no record is updated, and the method returns 0.
Simply, I have an application that has one page that deletes and then re-adds/refreshes the records into a table every 30 seconds. I have another page that runs every 45 seconds that reads the table data and builds a chart.
The problem is, in the read/view page, every once in a while I get a 0 value (from a max count) and the chart shows nothing. I have a feeling that this is happening because the read is being done at the exact same time the delete page has deleted all the records in the table but has not yet refreshed/re-added them.
Is there a way in my application I can hold off on the read when the table is being refreshed?
Best Regards,
Andy
C#
ASP.Net 4.5
SQL Server 2012
My code below is run in an ASP.Net 4.5 built Windows service. It deletes all records in the ActualPlot table and then refreshes/adds new records from a text file every 30 seconds. I basically need to block (lock?) any user from reading the ActualPlot table while the records are being deleted and refreshed. Can you PLEASE help me change my code to do this?
private void timer1_Tick(object sender, ElapsedEventArgs e)
{
// Open the SAP text files, clear the data in the tables and repopulate the new SAP data into the tables.
var cnnString = ConfigurationManager.ConnectionStrings["TaktBoardsConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(cnnString);
SqlConnection conndetail = new SqlConnection(cnnString);
SqlConnection connEdit = new SqlConnection(cnnString);
SqlCommand cmdGetProductFile = new SqlCommand();
SqlDataReader reader;
string sql;
// Delete all the records from the ActualPlot and the ActualPlotPreload tables. We are going to repopulate them with the data from the text file.
sql = "DELETE FROM ActualPlotPreload";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Delete Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conn.Close();
}
sql = "DELETE FROM ActualPlot";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Delete Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conn.Close();
}
// Read the SAP text file and load the data into the ActualPlotPreload table
sql = "SELECT DISTINCT [BoardName], [ProductFile], [ProductFileIdent] FROM [TaktBoards].[dbo].[TaktBoard] ";
sql = sql + "JOIN [TaktBoards].[dbo].[Product] ON [Product].[ProductID] = [TaktBoard].[ProductID]";
cmdGetProductFile.CommandText = sql;
cmdGetProductFile.CommandType = CommandType.Text;
cmdGetProductFile.Connection = conn;
conn.Open();
reader = cmdGetProductFile.ExecuteReader();
string DBProductFile = "";
string DBTischID = "";
string filepath = "";
string[] cellvalues;
DateTime dt, DateCheckNotMidnightShift;
DateTime ldSAPFileLastMod = DateTime.Now;
string MyDateString;
int FileRecordCount = 1;
while (reader.Read())
{
DBProductFile = (string)reader["ProductFile"];
DBTischID = (string)reader["ProductFileIdent"];
filepath = "c:\\inetpub\\wwwroot\\WebApps\\TaktBoard\\FilesFromSAP\\" + DBProductFile;
FileInfo fileInfo = new FileInfo(filepath); // Open file
ldSAPFileLastMod = fileInfo.LastWriteTime; // Get last time modified
try
{
StreamReader sr = new StreamReader(filepath);
FileRecordCount = 1;
// Populate the AcutalPlotPreload table from with the dates from the SAP text file.
sql = "INSERT into ActualPlotPreload (ActualDate, TischID) values (#ActualDate, #TischID)";
while (!sr.EndOfStream)
{
cellvalues = sr.ReadLine().Split(';');
if (FileRecordCount > 1 & cellvalues[7] != "")
{
MyDateString = cellvalues[7];
DateTime ldDateCheck = DateTime.ParseExact(MyDateString, "M/dd/yyyy", null);
DateTime dateNow = DateTime.Now;
string lsDateString = dateNow.Month + "/" + dateNow.Day.ToString("d2") + "/" + dateNow.Year;
DateTime ldCurrentDate = DateTime.ParseExact(lsDateString, "M/dd/yyyy", null);
string lsTischID = cellvalues[119];
if (ldDateCheck == ldCurrentDate)
{
try
{
conndetail.Open();
SqlCommand cmd = new SqlCommand(sql, conndetail);
cmd.Parameters.Add("#ActualDate", SqlDbType.DateTime);
cmd.Parameters.Add("#TischID", SqlDbType.VarChar);
cmd.Parameters["#TischID"].Value = cellvalues[119];
MyDateString = cellvalues[7] + " " + cellvalues[55];
dt = DateTime.ParseExact(MyDateString, "M/dd/yyyy H:mm:ss", null);
cmd.Parameters["#ActualDate"].Value = dt;
// Ignore any midnight shift (12am to 3/4am) units built.
DateCheckNotMidnightShift = DateTime.ParseExact(cellvalues[7] + " 6:00:00", "M/dd/yyyy H:mm:ss", null);
if (dt >= DateCheckNotMidnightShift)
{
cmd.ExecuteNonQuery();
}
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conndetail.Close();
}
}
}
FileRecordCount++;
}
sr.Close();
}
catch
{ }
finally
{ }
}
conn.Close();
// Get the unique TischID's and ActualDate from the ActualPlotPreload table. Then loop through each one, adding the ActualUnits
// AcutalDate and TischID to the ActualPlot table. For each unique TischID we make sure that we reset the liTargetUnits to 1 and
// count up as we insert.
SqlCommand cmdGetTischID = new SqlCommand();
SqlDataReader readerTischID;
int liTargetUnits = 0;
string sqlInsert = "INSERT into ActualPlot (ActualUnits, ActualDate, TischID) values (#ActualUnits, #ActualDate, #TischID)";
sql = "SELECT DISTINCT [ActualDate], [TischID] FROM [TaktBoards].[dbo].[ActualPlotPreload] ORDER BY [TischID], [ActualDate] ASC ";
cmdGetTischID.CommandText = sql;
cmdGetTischID.CommandType = CommandType.Text;
cmdGetTischID.Connection = conn;
conn.Open();
readerTischID = cmdGetTischID.ExecuteReader();
DBTischID = "";
DateTime DBActualDate;
string DBTischIDInitial = "";
while (readerTischID.Read())
{
DBTischID = (string)readerTischID["TischID"];
DBActualDate = (DateTime)readerTischID["ActualDate"];
if (DBTischIDInitial != DBTischID)
{
liTargetUnits = 1;
DBTischIDInitial = DBTischID;
}
else
{
liTargetUnits++;
}
try
{
conndetail.Open();
SqlCommand cmd = new SqlCommand(sqlInsert, conndetail);
cmd.Parameters.Add("#ActualUnits", SqlDbType.Real);
cmd.Parameters.Add("#ActualDate", SqlDbType.DateTime);
cmd.Parameters.Add("#TischID", SqlDbType.VarChar);
cmd.Parameters["#TischID"].Value = DBTischID;
cmd.Parameters["#ActualDate"].Value = DBActualDate;
cmd.Parameters["#ActualUnits"].Value = liTargetUnits;
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conndetail.Close();
}
}
conn.Close();
Library.WriteErrorLog("SAP text file data has been imported.");
}
If the data is being re-added right back after the delete (basically you know what to re-add before emptying the table), you could have both operation within the same SQL transaction, so that the data will be available to the other page only when it has been re-added.
I mean something like that :
public bool DeleteAndAddData(string connString)
{
using (OleDbConnection conn = new OleDbConnection(connString))
{
OleDbTransaction tran = null;
try
{
conn.Open();
tran = conn.BeginTransaction();
OleDbCommand deleteComm = new OleDbCommand("DELETE FROM Table", conn);
deleteComm.ExecuteNonQuery();
OleDbCommand reAddComm = new OleDbCommand("INSERT INTO Table VALUES(1, 'blabla', 'etc.'", conn);
reAddComm.ExecuteNonQuery();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
return false;
}
}
return true;
}
If your queries don't take too long to execute, you can start the two with a difference of 7.5 seconds, as there is a collision at every 90 seconds when the read/write finishes 3 cycles, and read/view finishes 2 cycles.
That being said, it's not a fool-proof solution, just a trick based on assumptions, in case you wan't to be completely sure that read/view never happens when read/write cycle is happening, try considering having a Read Lock. I would recommend reading Understanding how SQL Server executes a query and Locking in the Database Engine
Hope that helps.
I would try a couple of things:
Make sure your DELETE + INSERT operation is occurring within a single transaction:
BEGIN TRAN
DELETE FROM ...
INSERT INTO ...
COMMIT
If this isn't a busy table, try locking hints your SELECT statement. For example:
SELECT ...
FROM Table
WITH (UPDLOCK, HOLDLOCK)
In the case where the update transactions starts while your SELECT statement is running, this will cause that transaction to wait until the SELECT is finished. Unfortunately it will block other SELECT statements too, but you don't risk reading dirty data.
I was not able to figure this out but I changed my code so the program was not deleting all the rows in the ActualPlot table but checking to see if the row was there and if not adding the new row from the text file.
I have written a program to verify username and password using 3 tier architecture in Visual Studio 10. In the DAL, ExecuteNonQuery statement returns '-1'. But I want it to return '1' if username and password are correct or '0'if not correct.
Code snipped for DAL:
public class LoginDataAccess
{
SqlConnection con;
string constr = ConfigurationManager.ConnectionStrings["localhostakash"].ToString();
public int LoginData(LoginEntity elOj)
{
try
{
con = new SqlConnection(constr);
int result;
if(ConnectionState.Closed==con.State)
con.Open();
SqlCommand cmd = new SqlCommand("uspuserlogin", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Username", elOj.Username);
cmd.Parameters.AddWithValue("#Password", elOj.Password);
result = Convert.ToInt32(cmd.ExecuteNonQuery());
return result;
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
}
}
Code snippet for BLL:
public class LoginLogic
{
LoginDataAccess lda = new LoginDataAccess();
public int userValidate(LoginEntity le)
{
int result = 0;
try
{
result = Convert.ToInt32(lda.LoginData(le));
}
catch (Exception ex)
{
//response.write(ex.Message);
}
return result;
}
}
Code snippet for button function:
protected void Button1_Click(object sender, EventArgs e)
{
LoginLogic ll = new LoginLogic();
LoginEntity le = new LoginEntity();
int v;
le.Username = TextBox1.Text;
le.Password = TextBox2.Text;
v = Convert.ToInt32(ll.userValidate(le));
if (v == 1)
{
Label1.Text = "LOGGED IN SUCCESSFULLY!";
}
else
{
Label1.Text = "TRY AGAIN...";
}
}
Here is the documentation:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
Read more here: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executenonquery.aspx
You are calling a stored procedure "uspuserlogin". That's why ExecuteNonQuery returns -1.
You can return value as row if you need to know result of operation.
ALTER PROCEDURE [dbo].[uspuserlogin]
#username nvarchar(255),
#password nvarchar(255)
AS
BEGIN
SELECT COUNT(*) AS Found
FROM [Users]
WHERE [Username] = #username AND [Password] = #password
END
In code:
var obj = cmd.ExecuteScalar();
return (int)obj;
// Somewhere in code
if (loginDataAccess.LoginData(loginEntity) == 1)
// Authorize
Of course, you can transform it to bool for your convenience:
public bool LoginData(LoginEntity elOj)
{
try
{
con = new SqlConnection(constr);
int result;
if(ConnectionState.Closed==con.State)
con.Open();
SqlCommand cmd = new SqlCommand("uspuserlogin", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Username", elOj.Username);
cmd.Parameters.AddWithValue("#Password", elOj.Password);
var obj = cmd.ExecuteScalar();
return ((int)obj > 0);
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
}
I have some Steam trading bots and i am trying to insert to a database whether a trade was successful or not (true). You can see my code below. I get absolutely no errors and the regular trades, functions and console logging works fine. I check the db for content and nothing is there.
I am new to SQL in C#. Is someone able to tell me whats wrong with my code?
public override void OnTradeAccept()
{
bool didSomething = false;
if ((Validate()) || (IsAdmin && mode == ADMINMODE) || ChooseDonate)
{
bool success = Trade.AcceptTrade();
if (success) //makes sure trades were successfull
{
//I removed con details
string constr = "server=;database=;userid=;password=;";
MySqlConnection con = null;
try
{
con = new MySqlConnection(constr);
con.Open(); //open the connection
string insertTrue = "INSERT INTO trade_success(state) VALUES ('true')";
MySqlCommand command = new MySqlCommand(insertTrue, con);
command.ExecuteNonQuery();
}
catch (MySqlException err) //We will capture and display any MySql errors that will occur
{
Console.WriteLine("Error: " + err.ToString());
}
finally
{
if (con != null)
{
con.Close();
}
}
Log.Success("Trade was successful!");
//sendChatMessage(tradeSuccessMessage1);
sendChatMessage(tradeSuccessMessage2);
Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
}
else
{
Log.Warn("Trade might have failed.");
Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
}
}
}
Now this is my Code on Updating Records.
Data Access:
public int UpdateBatch(FillinEntity fin)
{
int result = 0;
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand dCmd = new SqlCommand("UpdatebyBatch", conn))
{
dCmd.CommandType = CommandType.StoredProcedure;
try
{
dCmd.Parameters.AddWithValue("#Batch", fin.Batch);
dCmd.Parameters.Add("#Date", SqlDbType.DateTime).Value = DateTime.Now.ToString();
dCmd.Parameters.AddWithValue("#User", fin.ModifiedBy);
result = Convert.ToInt32(dCmd.ExecuteScalar());
return result;
}
catch (SqlException ee)
{
throw ee;
}
finally
{
if (conn.State == ConnectionState.Open) conn.Close();
}
}
}
}
BUSINESS LOGIC:
public int UpdateBatch(FillinEntity fin)
{
DAL pDAL = new DAL();
try
{
return pDAL.UpdateBatch(fin);
}
catch
{
throw;
}
finally
{
pDAL = null;
}
}
UI:
FillinEntity fin = new FillinEntity();
BAL pBAL = new BAL();
try
{
fin.Batch = txtBACTHCODE.Text.Trim();
fin.ModifiedBy = lblUser.Text;
int result = pBAL.UpdateBatch(fin);
if (result > 0)
{
MessageBox.Show("Make Sure Batch is All Kitted!");
}
else
{
MessageBox.Show("Record Updated Successfully.");
}
SQL:
UPDATE dbo.FG_FILLIN SET
Status='SHIPPED'
,DateModified=#Date
,ModifiedBy=#User
WHERE Batch = #Batch and (Status='KITTED')
My Problem is It always return 0 result so my Message Box always Prompt Successfull even my Status is NOT KITTED.
Thanks in Regards!
Your stored procedure isn't returning a value thatExecuteScalar can make use of. You can use the ExecuteNonQuery method instead to return the number of affected records.
result = dCmd.ExecuteNonQuery();
In order for ExecuteScalar to return a value, you have to return one. You can modify your SQL to look like this:
UPDATE dbo.FG_FILLIN SET
Status='SHIPPED'
,DateModified=#Date
,ModifiedBy=#User
WHERE Batch = #Batch and (Status='KITTED')
SELECT ##ROWCOUNT
or you can use the ExecuteNonQuery method instead.