I am trying to return an integer from the database using ExecuteScalar(). However, when I run the query on the database itself, I get the correct answer, and c# gives me a 0 (Null) all the time. I know it returns a null because before i added id = Convert.ToInt32(command.ExecuteScalar()); it would give me an error telling me to make sure NULL is handled. I am expecting it to return a 3 btw.
private int getFamilyId()
{
int id = 0;
using (SqlConnection connection = new SqlConnection(Globaldata.ConnectionString))
{
using (SqlCommand command = new SqlCommand())
{
string sqlString = #"SELECT [Id] FROM [dbo].[FamilyDetails];";
command.Connection = connection;
command.CommandText = sqlString;
try
{
connection.Open();
id = Convert.ToInt32(command.ExecuteScalar());
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK);
}
finally
{
connection.Close();
}
return id;
}
}
}
When you do this:
string sqlString = #"SELECT [Id] FROM [dbo].[FamilyDetails];";
You don't want to do this:
id = Convert.ToInt32(command.ExecuteScalar());
Three things could go wrong here.
Problem #1:
If there are no rows in the table, command.ExecuteScalar() wil return Null.
Problem #2:
If there are any rows in the table, command.ExecuteScalar() wil return the value of the first rows it happens to encounter because the SELECT statement is not restricted to 1 value.
Problem #3:
If the Id column is not declared as NOT NULL command.ExecuteScalar() could return a DbNull, which which makes no sense when converted to an Integer.
Try and see what happens when there are 0 or 1 or 2 records in the table.
--UPDATE--
It works now, My connection string had one character missing. I think it happened when I took out the connection Timeout part of the connection string.
Thank you for your suggestions!!!
Related
I am creating a simple project on c#.net. I want to put the AutoNo textbox in my program. I have put but it is not working. it shown the error while ran program error said that
Value cannot be null Parameter name: Stringmscorlib
Code what I tried I attached below
public void Load()
{
SqlConnection Con = new SqlConnection("Data Source=.;Initial Catalog=test1;Persist Security Info=True;User ID=sa;Password=admin123");
Con.Open();
cmd = new SqlCommand("select id from records", Con);
Data = cmd.ExecuteReader();
while (Data.Read() != false)
{
auto = int.Parse(Data[0].ToString());
}
try
{
int newid = auto;
int id = newid + 1;
this.textBox1.Text = "S00" + id.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.Source);
}
Data.Close();
}
}
There are two problems I can see here; the first would be: what if there are zero rows? what is auto then? is it null? then int.Parse(null) will fail. You don't actually show where auto is declared, which makes this bit a little hard to intuit about.
The other possibility is here:
auto = Data.GetString(0);
in which case: this is simply a null database value. Check for that, and handle it:
if (Data.IsDBNull(0))
{ ... do whatever; perhaps just "continue" }
else
{
auto = Data.IsDBNull(0);
// and process it, etc
}
But frankly, you're making life hard for yourself here; here's the same thing with a tool like Dapper:
using (var conn= new SqlConnection("...whatever..."))
{
// here we're asserting *exactly* zero or one row
string auto = conn.QuerySingleOrDefault<string>("select id from records");
if (auto == null)
{ ... do something else? ... }
else
{
var newid= int.Parse(auto);
}
}
Note: your query could currently return any number of rows; since the code only processes the last value, I suggest that the SQL needs fixing; perhaps MAX, MIN, or TOP 1 with an ORDER BY clause; i.e. something like select MAX(id) as [id] from records. Note, however, that this sounds like a scenario where you should probably have used SCOPE_IDENTITY() in some query that added or inserted the value. And an id should very rarely be a string.
Parse method is not able to handle null value. Assuming auto is variable name.
instead of this
int newid = Int32.Parse(auto);
use something like below
int newid=0;
int.TryParse(auto, out newid);
When I use:
START TRANSACTION;
INSERT IGNORE INTO users (Name, ...) VALUES ('user1',..) ON DUPLICATE KEY UPDATE lastSeen=NOW();
SELECT LAST_INSERT_ID();
COMMIT;
When i run this query from my sql client I get the last inserted id as expected.
But what if the user already exists?(table uniquness). So no new id is created. But now when I run the same query from my sql client still i get the id as expected.
But! when I run it from my C# code and use mysql.reader to query the result I receive 0. Why is that??
If instead of SELECT LAST_INSERT_ID() I use SELECT id FROM users ORDER BY id DESC LIMIT 1 I get the right id again.
EDIT!
This is not a duplicate of the suggested topic. In that topic the answer says that the auto-incremented is not the primary key, thats not my case! also as I mark it does return the right id when i use the mysql client! The problem occures only when I run it from my c# code!
My C# code:
using (var conn = new MySqlConnection(connString))
{
try
{
conn.Open();
var command = conn.CreateCommand();
command.CommandText = strSQL;
MySqlDataReader reader;
string result = "";
try
{
reader = command.ExecuteReader();
if (reader.Read())
result = reader[0].ToString();
}
catch (Exception ex)
{
throw new MySqlException("SQL Error: " + ex.ToString());
}
reader.Close();
return result;
}
}
I have found a work around, simple CASE clause does the job:
START TRANSACTION;
INSERT IGNORE INTO users (Name, ...) VALUES ('user1',..) ON DUPLICATE KEY UPDATE lastSeen=NOW();
SELECT CASE WHEN LAST_INSERT_ID()=0 THEN (SELECT id FROM users WHERE Name = 'user1') ELSE LAST_INSERT_ID() END;
COMMIT;
Now in case the user exists, we simply query the id, If it doest not exists, the LAST_INSERT_ID() will give us the right id
From what I read there https://stackoverflow.com/a/15057619/4421474
Your code could be transformed to:
using (var conn = new MySqlConnection(connString))
{
conn.Open();
var command = conn.CreateCommand();
command.CommandText = strSQL; <-- just insert part like "START ... INSERT ... COMMIT;"
command.ExecuteNonQuery();
string result = command.LastInsertedId;
return result;
}
Sorry I am not c# expert so some syntax could be broken.
I guess this answer:
Just my 50 cents for this issue, I simply noticed that you won't get a LAST_INSERT_ID greater than 0 if your table has no AUTO_INCREMENT set to an index
that i found here MySQL: LAST_INSERT_ID() returns 0 is the good one.
I'm trying to get the max id of the table category using this code
string maxid = "";
string query = "SELECT MAX(Cat_ID) + 1 FROM Category";
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["JokerCafe"].ConnectionString);
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
maxid = cmd.ExecuteNonQuery().ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
return maxid;
I run this query in sql it is returning exact value but when try to execute it from code it returns -1. Kindly guide me what's going wrong with it?
ExecuteNonQuery() will return the affected row count. For example if you are trying to execute any update statement or delete statement through ExecuteNonQuery() method then it will return the number of affected rows.
But, if you want to fetch a value from specific field then you need to try ExecuteScalar() method. It will return Object type value. Using this method you can fetch only a single value record.
object val = command.ExecuteScalar();
if (val != null)
{
//Do your stuff here.
}
ExecuteScaler is your solution
It executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
so do modify your code to
maxid = cmd.ExecuteScalar().ToString();
or
maxid = cmd.ExecuteScalar() as string; //to be safe side if return value is null
and you'll get the value expected from the query
I am trying to check if there is a row present in a SQL Server table or not.
If the row exists (on a particular TicketID), it should show a messagebox that you can't continue further as there is already an entry in database. But if there isn't, it should insert some records (on that particular TicketID).
I tried try and catch but wasn't able to do it :
Here is the code of query: (hardcoded ticketID for example)
bool no;
try
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ST"].ConnectionString.ToString());
con.Open();
cmd.CommandText = "SELECT EngineerVisited from tblTicketTechnical where TicketID=1";
cmd.Connection = con;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
bool = rdr.GetBoolean(0);
}
con.Close();
}
catch
{
MessageBox.Show("Cannot continue");
}
I would really appreciate if someone could suggest a function that will return true if row is found and return false, if it isn't.
You should follow the same logic in code as the logic you state in English: if there's already a ticket show a message and if not, insert some data.
var checkQuery = "SELECT COUNT(*) FROM tblTicketTechnical where TicketID=1";
var command = new OleDbCommand(checkQuery, con);
con.Open();
int count = (int)command.ExecuteScalar();
if(count > 0)
{
//Already exists, show message
}
else
{
var insertQuery = "INSERT INTO tblTicketTechnical(col1, col2) VALUES('val1', val2')";
con = new OleDbCommand(insertQuery, con);
con.ExecuteNonQuery();
}
Please mind that this is written out of my head and not tested. Nor have I implemented exception handling. This is just to show the logic how you can perform what you want to achieve.
You can use HasRows property of SQLDataReader.
A catch block will only be executed if your code throws an exception. Here it is simply not happening.
Instead of Try/Catch use if statements and checks on your query results.
Create procedure and code like this
IF NOT EXISTS (SELECT 1 FROM youtable WHERE id= #id)
BEGIN
RAISERROR ('Record Exists', 16, 2)
END
ELSE
Begin
INSERT INTO YOURTABEL(COLUM1,COLUM2) VALUES(VALUE1, VALUE2)
END
and then by try catch you can show message to user
You can use DataTableReader.HasRows Property
The HasRows property returns information about the current result set
I am trying to run a stored procedure and for some reason it keeps telling me "Specified cast is not valid". the "hidSelectedExpenseIDs" is a hidden field that gets populated with a javascript array of id's.
Example: the "hidSelectedExpenseIDs.Value" would look like "123,124,125,126". Hence why I have the .Split(',') in there.
Here is my code:
public void hasExhistingExpenseInvoice()
{
string[] Expenses = hidSelectedExpenseIDs.Value.Split(',');
//check if there is an existing invoice. Then report back to the user so the
//user knows if he/she has to check overwrite option.
bool invoiceExists = false;
foreach (var expense in Expenses)
{
var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["OSCIDConnectionString"].ToString());
var command = new SqlCommand("p_CaseFiles_Expenses_InvoiceExhists", connection);
command.Parameters.Add(new SqlParameter("#ExpenseID", SqlDbType.Int));
command.Parameters["#ExpenseID"].Value = Convert.ToInt32(expense);
command.CommandType = CommandType.StoredProcedure;
try
{
connection.Open();
invoiceExists = (bool)command.ExecuteScalar();
if (invoiceExists)
{
//previous invoice exhists
Warning1.Visible = true;
Warning1.Text = "There is an exhisting Invoice.";
}
}
catch (SqlException sql)
{
lblStatus.Text = "Couldn't connect to the Database - Error";
lblStatus.ForeColor = System.Drawing.Color.Red;
}
catch (Exception ex)//catches exception here
{
lblStatus.Text = "An error occured";
lblStatus.ForeColor = System.Drawing.Color.Red;
}
finally
{
if (connection.State == ConnectionState.Open)
connection.Close();
}
}
}
this is my stored procedure:
ALTER PROCEDURE dbo.[InvoiceExhists]
#ExpenseID int
AS
BEGIN
SELECT InvNumber FROM dbo.Expenses from ExpID = #ExpenseID
END
The logic is faulty.
Your Query returns a number, and you are trying to cast it directly to a Boolean, this can't be done in C#.
Some languages will interpret any non-zero as true, it is not the case for C# and it will throw an exception.
You will need to compare the returned value.
In this case, you should just check if there is a value, because NULL will be returned if the invoice does not exist.
This would look like this :
invoiceExists = command.ExecuteScalar() != null ;
Also I recommend reading this thread and consider using UDF instead of scalar Stored Procedures.
change your stored procedure .This fits your requirement
ALTER PROCEDURE [dbo].[InvoiceExhists]
#ExpenseID int
AS
BEGIN
if exists(select * Expenses where ExpID = #ExpenseID)
select 1
else
select 0
END
The exception is likely caused by invoiceExists = (bool)command.ExecuteScalar(); considering its the only casting that happens within the try statement. You need to look at the return result of ExecuteScalar() to solve your problem.