Int Result Doesnt Increment using Cmd.ExecuteScalar PRoblem? - c#

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.

Related

Select for login and update at the same time

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.

How to return data using sqCommand.ExecuteReader();?

I have Sqlite method that makes SELECT query:
try {
myConn.Open();
using(SQLiteCommand sqCommand = new SQLiteCommand(sql, myConn)) {
sqCommand.CommandText = sql;
SQLiteDataReader reader = sqCommand.ExecuteReader();
return reader.GetString(0);
}
} catch (Exception e) {
// do exception handling
}
I tried to get last inserted id:
sql = 'SELECT id FROM Pacients ORDER BY id DESC LIMIT 1';
I tried to di that like:
return reader.GetString(0);
it's throwing me down on exception "No current row"
After calling ExecuteReader you need to call Read to position on the first record of the dataset. Read returns true/false to inform you if there are records to read. So your code changes to
try {
myConn.Open();
using(SQLiteCommand sqCommand = new SQLiteCommand(sql, myConn)) {
sqCommand.CommandText = sql;
SQLiteDataReader reader = sqCommand.ExecuteReader();
if(reader.Read())
return reader.GetString(0);
else
return ""; // or whatever you want to return if no records are present
}
} catch (Exception e) {
// do exception handling
}
Said that, remember that if you want to retrieve just one column from a single row like you have in your query then it is better to use ExecuteScalar instead of ExecuteReader
try {
myConn.Open();
using(SQLiteCommand sqCommand = new SQLiteCommand(sql, myConn)) {
sqCommand.CommandText = sql;
object result = sqCommand.ExecuteScalar();
return result != null ? result.ToString() : "";
}
} catch (Exception e) {
// do exception handling
}

Problems inserting items in a database using SQLite in C#

i am trying to insert items in a database using SQLite but when i call loadfunction i receive an error like out of index. I think the problem is when i call add function. I checked parameters values and all seems to be ok, but the elements are not inserted in the table. Bellow you will see my table, add function and load function.
The table:
CREATE TABLE `Fisiere` (
`Nume` TEXT,
`Dimensiune` INTEGER,
`Data` BLOB,
`Rating_imdb` REAL,
`Cale` TEXT
);
The insert function:
public void addFisier(DirectorVideo[] directors)
{
var dbCommand = new SQLiteCommand();
dbCommand.Connection = _dbConnection;
dbCommand.CommandText = "insert into Fisiere(Nume, Dimensiune, Data, Rating_imdb, Cale) values(#nume, #dimensiune, #data, #rating_imdb, #cale);";
try {
_dbConnection.Open();
dbCommand.Transaction = _dbConnection.BeginTransaction();
for (int i = 0; i < directors.Length - 1; i++)
{
for (int j = 0; j < directors[i].nrFisiere; j++)
{
var numeParam = new SQLiteParameter("#nume");
numeParam.Value = directors[i].fisiere[j].numeFisier;
var dimensiuneParam = new SQLiteParameter("#dimensiune");
dimensiuneParam.Value = directors[i].fisiere[j].dimensiune;
var dataParam = new SQLiteParameter("#data");
dataParam.Value = directors[i].fisiere[j].data;
var ratingParam = new SQLiteParameter("rating_imdb");
IMDb rat = new IMDb(directors[i].fisiere[j].numeFisier);
ratingParam.Value = rat.Rating;
var caleParam = new SQLiteParameter("cale");
caleParam.Value = directors[i].cale;
Console.WriteLine(numeParam.Value);
dbCommand.Parameters.Add(numeParam);
dbCommand.Parameters.Add(dimensiuneParam);
dbCommand.Parameters.Add(dataParam);
dbCommand.Parameters.Add(ratingParam);
dbCommand.Parameters.Add(caleParam);
Console.WriteLine(caleParam.Value);
dbCommand.Transaction.Commit();
Console.WriteLine("A fost inserat");
}
}
}
catch (Exception)
{
Console.WriteLine("muie");
dbCommand.Transaction.Rollback();
throw;
}
finally
{
if (_dbConnection.State != ConnectionState.Closed) _dbConnection.Close();
}
}
Load file function
public void LoadFiles()
{
const string stringSql = "PRAGMA database_list";
try
{
_dbConnection.Open();
SQLiteCommand sqlCommand = new SQLiteCommand(stringSql, _dbConnection);
SQLiteDataReader sqlReader = sqlCommand.ExecuteReader();
try
{
while (sqlReader.Read())
{
Console.WriteLine("se afiseaza");
Console.WriteLine((long)sqlReader["Id_fisier"]);
Console.WriteLine((string)sqlReader["Nume"]);
Console.WriteLine((long)sqlReader["Dimensiune"]);
Console.WriteLine(DateTime.Parse((string)sqlReader["Data"]));
Console.WriteLine((long)sqlReader["Rating_imdb"]);
Console.WriteLine((string)sqlReader["Cale"]);
}
}
finally
{
// Always call Close when done reading.
sqlReader.Close();
}
}
finally
{
if (_dbConnection.State != ConnectionState.Closed) _dbConnection.Close();
}
}
You are going to need to Commit your transaction. You call BeginTransaction() but you never commit your transaction so the data never gets written to the DB. Check this out for the details and workflow with Transactions. https://www.sqlite.org/lang_transaction.html
The other problem is that your Transactions and your Commands are all out of order. You need to execute your commands within your transaction and then commit the transaction.
public void addFisier(DirectorVideo[] directors)
{
SQLiteTransaction dbTrans;
try
{
_dbConnection.Open();
// Start Transaction first.
dbTrans = _dbConnection.BeginTransaction();
for (int i = 0; i < directors.Length - 1; i++)
{
for (int j = 0; j < directors[i].nrFisiere; j++)
{
// Create commands that run based on your number of inserts.
var dbCommand = new SQLiteCommand();
dbCommand.Connection = _dbConnection;
dbCommand.CommandText = "insert into Fisiere(Nume, Dimensiune, Data, Rating_imdb, Cale) values(#nume, #dimensiune, #data, #rating_imdb, #cale);";
dbCommand.Transaction = dbTrans;
var numeParam = new SQLiteParameter("#nume");
numeParam.Value = directors[i].fisiere[j].numeFisier;
var dimensiuneParam = new SQLiteParameter("#dimensiune");
dimensiuneParam.Value = directors[i].fisiere[j].dimensiune;
var dataParam = new SQLiteParameter("#data");
dataParam.Value = directors[i].fisiere[j].data;
var ratingParam = new SQLiteParameter("rating_imdb");
IMDb rat = new IMDb(directors[i].fisiere[j].numeFisier);
ratingParam.Value = rat;
var caleParam = new SQLiteParameter("cale");
caleParam.Value = directors[i].cale;
Console.WriteLine(numeParam.Value);
dbCommand.Parameters.Add(numeParam);
dbCommand.Parameters.Add(dimensiuneParam);
dbCommand.Parameters.Add(dataParam);
dbCommand.Parameters.Add(ratingParam);
dbCommand.Parameters.Add(caleParam);
Console.WriteLine(caleParam.Value);
Console.WriteLine("A fost inserat");
// Actually execute the commands.
dbCommand.ExecuteNonQuery();
}
}
// If everything is good, commit the transaction.
dbTrans.Commit();
}
catch (Exception)
{
Console.WriteLine("muie");
dbTrans.Rollback();
throw;
}
finally
{
if (_dbConnection.State != ConnectionState.Closed) _dbConnection.Close();
}
}
Here is also a snippet from the SQLiteTransaction Class documentation. I suggest reading it: https://www.devart.com/dotconnect/sqlite/docs/Devart.Data.SQLite~Devart.Data.SQLite.SQLiteTransaction.html
public static void RunSQLiteTransaction(string myConnString) {
using (SQLiteConnection sqConnection = new SQLiteConnection(myConnString)) {
sqConnection.Open();
// Start a local transaction
SQLiteTransaction myTrans = sqConnection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
SQLiteCommand sqCommand = sqConnection.CreateCommand();
try {
sqCommand.CommandText = "INSERT INTO Dept(DeptNo, DName) Values(52, 'DEVELOPMENT')";
sqCommand.ExecuteNonQuery();
sqCommand.CommandText = "INSERT INTO Dept(DeptNo, DName) Values(62, 'PRODUCTION')";
sqCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Both records are written to database.");
}
catch (Exception e) {
myTrans.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Neither record was written to database.");
}
finally {
sqCommand.Dispose();
myTrans.Dispose();
}
}
}

What is the return value of ExecuteNonQuery statement?

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();
}
}

SELECT query on Nvarchar column returning Int

I'm trying to return a string value from my database but instead the query is returning "0" although the SELECT query is targeting a nvarchar column.
The query is valid and runs correctly, returning "KYO" when run using SQL-SMS.
This is the method, which works as expected in the other place I use it, that I use for returning data:
public static object GetData(string sql, SqlParameter[] parameters)
{
try
{
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = sql;
if (parameters != null)
{
foreach (var parameter in parameters)
{
if (parameter != null)
command.Parameters.Add(parameter);
}
}
object result = null;
SqlParameter returnValue = new SqlParameter("ReturnValue", result);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
connection.Open();
command.ExecuteScalar();
result = command.Parameters["ReturnValue"].Value;
return result;
}
}
}
catch (Exception)
{
throw;
}
}
}
This is the method which is throwing a cast exception as it's returning an int instead of a string:
private static String GetManufacturerCode(Int32 manufacturerID)
{
try
{
StringBuilder sql = new StringBuilder();
sql.Append("SELECT ManufacturerCode FROM Manufacturers WHERE ManufacturerID = #ID");
SqlParameter id = new SqlParameter("#ID", manufacturerID);
return(String)DB.GetData(sql.ToString(), new[] { id });
}
catch (Exception)
{
throw;
}
}
I also set returnValue.DbType = DbType.String; as a test and this still returned an integer.
An example of where I use the GetData(...) method successfully is:
public static Int32 GetMonitoredCount()
{
try
{
String GetMonitoredCount = "SELECT COUNT(*) FROM Devices WHERE Monitored = 1 ";
return (Int32)DB.GetData(GetMonitoredCount, null);
}
catch (Exception)
{
throw;
}
}
I considered it might be returning a boolean bit but as my query executes correctly I'd have assumed it would return 1 not 0.
Why is an integer being returned? How can I return a string using my pattern?
ReturnValue always returns int - this is by design.
Instead of this entire block
object result = null;
SqlParameter returnValue = new SqlParameter("ReturnValue", result);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
connection.Open();
command.ExecuteScalar();
result = command.Parameters["ReturnValue"].Value;
Try
connection.Open();
object result = command.ExecuteScalar();
This will return you real result of your SQL statement
Method ExecuteScalar itself is capable of returning value - it return first column of the first row of the resultset and is ideal when your query returns a single value.

Categories