SQL allow null in table in C# - c#

Using SQL Server 2008, WinForms C# .NET 4.5, Visual Studio 2012.
I have a query that currently updates a table with some information from a GridView.
Below is the code that calls the stored procedure:
public void UpdateMain(string part, int? pareto)
{
try
{
using (SqlConnection AutoConn = new SqlConnection(conn32))
{
AutoConn.Open();
using (SqlCommand InfoCommand = new SqlCommand())
{
using (SqlDataAdapter infoAdapter = new SqlDataAdapter(InfoCommand))
{
InfoCommand.Connection = AutoConn;
InfoCommand.CommandType = CommandType.StoredProcedure;
InfoCommand.CommandText = "dbo.updateMain";
InfoCommand.Parameters.AddWithValue("#part", part);
InfoCommand.Parameters.AddWithValue("#pareto", pareto);
InfoCommand.CommandTimeout = 180;
InfoCommand.ExecuteNonQuery();
}
}
}
}
catch (Exception e)
{
//MessageBox.Show("Error in connection :: " + e);
}
}
And here's the SQL:
ALTER PROCEDURE [dbo].[updateMain]
#part varchar(255),
#Pareto int
as
UPDATE dbo.ParetoMain
SET NewPareto = #Pareto
WHERE Part = #part
Nothing fancy as you can see. The problem I have is the Newpareto doesn't have to have a value, so I need it to allow nulls. I made sure the table allows nulls. And in my C# code I made sure to use nullable int, but when I run the code I get the error:
Exception:Thrown: "Procedure or function 'updateMain' expects parameter '#Pareto', which was not supplied." (System.Data.SqlClient.SqlException)
A System.Data.SqlClient.SqlException was thrown: "Procedure or function 'updateMain' expects parameter '#Pareto', which was not supplied."
So how do I stop this error and get the null into the table?

The problem is that the parameter is expected, but not added if the nullable value is null. You need to address this by either:
Manually setting it do DBNull.Value as in: InfoCommand.Parameters.AddWithValue("#Pareto", (object)pareto ?? DbNull.Value);
Or by making the parameter optional as in: #Pareto int = null
Your stored procedure could look like this if you want to make the parameter optional:
ALTER PROCEDURE [dbo].[updateMain]
#part varchar(255),
#Pareto int = null
as
UPDATE dbo.ParetoMain SET NewPareto =#Pareto WHERE Part = #part
EDIT
I take it from the accepted answer that you need to cast to object due to type mismatch problems. I'm fixing my answer for the sake of completeness.

use
InfoCommand.Parameters.AddWithValue("#Pareto", (Object)pareto ?? DBNull.Value);

Try this:
if (pareto != null)
{
InfoCommand.Parameters.AddWithValue("#pareto", pareto);
}
else
{
InfoCommand.Parameters.AddWithValue("#pareto", DBNull);
}

Related

Setting DEFAULT value using SQLiteParameter

My query is supposed to add an additional column "_DisableAccounting" to the "Settings_Global" table, specifying a DEFAULT value using a SQLiteParemeter.
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT #defaultValue;
When the SQLiteCommand is executed, #defaultValue should be replaced by the supplied parameter.
// ....
SQLiteParameter defaultValueParam = null;
if (defaultValue != null) {
query += " DEFAULT #defaultValue`";
defaultValueParam = new SQLiteParameter { ParameterName = "#defaultValue", Value = defaultValue };
}
query += ";";
using (SQLiteCommand cmd = _Connection.CreateCommand()) {
cmd.CommandText = query;
if (defaultValueParam != null) {
cmd.Parameters.Add(defaultValueParam);
}
cmd.ExecuteNonQuery();
}
// ....
However, I get the error "'SQL logic error or missing database near
#defaultValue": syntax error'". So it seems that the command is never replacing #defaultValue with the actual value.
Why isn't this working? I am doing essentially the same with MySQL (my application can optionally use MySQL) and it is working.
You appear to have a spurious grave accent. That is #defaultValue is followed grave accent, when it likely shouldn't be.
Try changing
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT #defaultValue`;
to
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT #defaultValue;
or to
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT `#defaultValue`;
When doing ALTER TABLE, SQLite does not modify the column definition in any way and just inserts it directly at the end of the CREATE TABLE statement.
This means that the parameter marker would end up in that CREATE TABLE statement, which would result in the parameter value not being available when the statement is interpreted later.
You have to insert the default value directly into the SQL command.

C# changes output parameter to invalid value and throws error

Using:
Visual Studio 2010
SQL Server 2012
I have a stored procedure, which inserts a new record in the DB and returns the new record ID as an output parameter. I ran the sp manually and it works.
If I run it from my C# application, and I read the output parameter afterwards, C# reads a *, instead of the number.
I changed the sp to write the output parameter to a table before outputting it. I always get the correct record ID in this table.
The C# code that reads the output parameter is used (without any changes) in several other applications and works. It is used for other sp's in this application and it works. I've added the code nevertheless:
public string SpOutputParameter(string sSpName, SpParameter[] oParam, bool
bKeepConnectionOpen = false)
{
// Set return value to -1
int iReturnValue = -1;
// SP Command
SqlCommand Cmd = new SqlCommand(sSpName, this.Db); // Command (exec sp)
Cmd.CommandType = CommandType.StoredProcedure; // Type of command
try // Try to get results
{
// Add the parameters
this.AddParameters(oParam, Cmd);
this.AddReturnValue(Cmd);
// Get the results
this.OpenDatabase();
Cmd.ExecuteNonQuery();
if (!bKeepConnectionOpen)
this.Db.Close();
// Get the return value
iReturnValue = GetReturnValue(Cmd);
// If the sp fails, throw an exception (to be caught)
if (iReturnValue != 0)
throw new Exception("The database returned a return value of " + Convert.ToString(iReturnValue != 0));
// Get the output parameter to return
foreach (SqlParameter parameter in Cmd.Parameters)
{
if (parameter.Direction == ParameterDirection.Output ||
parameter.Direction == ParameterDirection.InputOutput)
return Convert.ToString(parameter.Value);
}
}
catch (Exception Ex)
{
// Edit the message, rethrow exception
throw new Exception(
"Failed to run sp '" + sSpName + "'",
Ex);
}
finally // Dispose of used objects
{
// Dispose the command
Cmd.Dispose();
Cmd = null;
}
// If the code gets here, there was no output parameter.
// return null...
return null;
}
When I debug, I see the value of the parameter as a * on the parameter.Value property. ('return Convert.ToString(parameter.Value);' line)
At the moment my app doesn't work, I need to get the value of the output parameter. Can someone please help me figure out why I get a * (in C#) instead of the actual output parameter value?
Thank you!
Based on your explanation that your stored procedure is inserting a new record and returning that value, and the fact that your return type is string, I am going to guess that your output parameter is a char or varchar, and you do something like this:
SET #VarCharParameter = SCOPE_IDENTITY();
In which case, if your char/varchar is not large enough to store the int, it will become *, e.g.
SELECT CONVERT(CHAR(2), 10000);
The solution to this is to use the correct types. If you are looking to return an integer, then use an INT parameter.
It seems to be some types converting issue. Try just casting like:
return (string)parameter.Value;
Since stored procedure being used is not shown here, kindly make sure that OUTPUT keyword is used in StoredProcedure with the parameters required to be sent back for C#
e.g. > #outputParameter Varchar(100) OUTPUT
Also while adding SQL parameters to cmd object in your C# code, check that the direction is set to output
e.g.SqlParameter OutputParam = new SqlParameter("#OutputParam", SqlDbType.VarChar);
OutputParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(OutputParam);
At Last, try to close database connection (this.Db.Close()) after you have got everything you need from the cmd object.

Stored procedure having unspecified values altough value is passed

Stored procedure executes fine if executed in SQL Server Management Studio.
In C# (Winforms) I have the following code:
InsertWarning.Parameters.AddWithValue("#idUser", userIDAuth);
InsertWarning.Parameters.AddWithValue("#idPass", idPass);
if (Privileged)
MessageWarning += " gave you privileged access to note " + Description;
else
MessageWarning += " gave you access to note " + Description;
InsertWarning.Parameters.AddWithValue("#Message", MessageWarning);
InsertWarning.ExecuteNonQuery();
InsertWarning.Parameters.Clear();
When ExecuteNonQuery() runs it stops saying the #idUser has no value.
Stored procedure in C#:
SqlCommand InsertWarning = new SqlCommand("_spInsertWarnings", TeamPWSecureBD);
InsertAuths.CommandType = CommandType.StoredProcedure;
Stored procedure in SQL:
[dbo].[_spInsertWarnings]
#idUser int, #idPass int, #Message nvarchar(MAX)
AS
INSERT INTO Warnings
VALUES(#idUser, #idPass, #Message)
using (SqlConnection con = new SqlConnection(dc.Con))
{
using (SqlCommand cmd = new SqlCommand("_spInsertwarnings", con))
{
cmd.CommandType = CommandType.StoredProcedure;
//Please Make SqlDataType as per your Sql ColumnType
cmd.Parameters.Add("#idUser", SqlDbType.VarChar).Value = userIDAuth;
cmd.Parameters.Add("#idPass", SqlDbType.VarChar).Value = idPass;
con.Open();
cmd.ExecuteNonQuery();
}
}
The question in this post looks similar to yours:
Stored procedure or function expects parameter which was not supplied
Have you tried using the .Parameters.Add("fieldname", type, value) instead? I'm wondering if even though you are seeing the value 8 in a debug session, it's not being recognized when you do a stored procedure call.
Thinking about this again, my guess is you're missing a different parameter than #idUser, and that parameter does not have a default value assigned. Sometimes SQL Server reports the wrong name back for a parameter missing a value.
Look at your proc header and confirm that you're passing all the required parameters that the proc expects, or that you have sensible defaults assigned for the ones you don't always want to pass.
I guess this might work, i have posted the code from where you are adding.
InsertWarning.Parameters.Add("#idUser", SqlDbType.Int);
InsertWarning.Parameters["#idUser"].Value = userIDAuth;
InsertWarning.Parameters.AddWithValue("#idPass", idPass);
try
{
connection.Open();
InsertWarning.ExecuteNonQuery()
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

Error Converting datatype nvarchar to int from c# to sql

Hi Guys please help me out in my code where I got stuck and went wrong, I have two tables; one employee table and another branch table. The branch id will be stored in employee table which is a foreign key. When I'm inserting the data through stored procedure where I kept the code like bleow
Create procedure [dbo].[Insertemployee]
#d28 int,#d1 nchar(15),#d2 nchar(30),#d3 int,#d4 nchar(10),#d5 nchar(20),#d6 nchar(30),#d7 varchar(100),#d8 nchar(100),#d9 nchar(10),#d10 nchar(10),#d11 nchar(30),#d12 nchar(30),#d13 nchar(30),#d14 nchar(30),#d15 nchar(30),#d16 date,#d17 varchar(100),#d18 int,#d19 int,#d20 int,#d21 int,#d22 int,#d23 int,#d24 int,#d25 image,#d26 date,#d27 date,#d29 nchar(10)
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
BEGIN TRANSACTION
insert into Employee(Id,StaffID,StaffName,Branchid,Gender,DOB,FatherName,PermanentAddress,Country,PhoneNo,MobileNo,DateOfJoining,VisaNumber,PassportNumber,PassportExpiryDate,NationalityID,NationalityIDExpiryDate,Designation,BasicSalary,CostOfAllowance,HRA,TeaAndSnacks,Bonus,Loan,OtherDeduction,Picture,createddate,lastmodified,Active) VALUES (#d28,#d1,#d2,(select branchid from Branch where Branch.BranchName=#d3),#d4,#d5,#d6,#d7,#d8,#d9,#d10,#d11,#d12,#d13,#d14,#d15,#d16,#d17,#d18,#d19,#d20,#d21,#d22,#d23,#d24,#d25,#d26,#d27,#d29);
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT >0
BEGIN
ROLLBACK TRANSACTION
END
EXECUTE uspLogError
END CATCH
END;`
and my front end code is below
cmd = new SqlCommand("InsertEmployee");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.AddWithValue("#d28",txtID.Text);
cmd.Parameters.AddWithValue("#d26", System.DateTime.Now);
cmd.Parameters.AddWithValue("#d27", System.DateTime.Now);
cmd.Parameters.AddWithValue("#d1", txtStaffID.Text);
cmd.Parameters.AddWithValue("#d2",txtStaffName.Text);
cmd.Parameters.AddWithValue("#d3",txtDepartment.Text);
cmd.Parameters.AddWithValue("#d4",cmbGender.Text);
cmd.Parameters.AddWithValue("#d6",txtFatherName.Text);
cmd.Parameters.AddWithValue("#d7",txtPAddress.Text);
cmd.Parameters.AddWithValue("#d8",txtTAddress.Text);
cmd.Parameters.AddWithValue("#d9",txtPhoneNo.Text);
cmd.Parameters.AddWithValue("#d10",txtMobileNo.Text);
cmd.Parameters.AddWithValue("#d11",dtpDateOfJoining.Value);
cmd.Parameters.AddWithValue("#d12",visanumber.Text.Trim());
cmd.Parameters.AddWithValue("#d14",PassportExpirydate.Text);
cmd.Parameters.AddWithValue("#d15",NationalityID.Text.Trim());
if (NationalityID.Text == "")
{
cmd.Parameters.AddWithValue("#d16", "");
}
else
{
cmd.Parameters.AddWithValue("#d16", NationalityExpirydate.Value);
}
cmd.Parameters.AddWithValue("#d17",txtDesignation.Text.Trim());
cmd.Parameters.AddWithValue("#d13",Passportnumber.Text.Trim());
cmd.Parameters.AddWithValue("#d18",Convert.ToInt32(txtBasicSalary.Text.Trim()));
if (txtLIC.Text == "")
{
cmd.Parameters.AddWithValue("#d19", 0);
}
else
{
cmd.Parameters.AddWithValue("#d19",Convert.ToInt32(txtLIC.Text.Trim()));
}
if (txtGrpInsurance.Text == "")
{
cmd.Parameters.AddWithValue("#d21", 0);
}
else
{
cmd.Parameters.AddWithValue("#d21",Convert.ToInt32(txtGrpInsurance.Text.Trim()));
}
if (txtFamilyBenefitFund.Text == "")
{
cmd.Parameters.AddWithValue("#d22",0);
}
else
{
cmd.Parameters.AddWithValue("#d22",Convert.ToInt32(txtFamilyBenefitFund.Text.Trim()));
}
if (txtLoans.Text == "")
{
cmd.Parameters.AddWithValue("#d23",0);
}
else
{
cmd.Parameters.AddWithValue("#d23",Convert.ToInt32(txtLoans.Text.Trim()));
}
if (txtOtherDeductions.Text == "")
{
cmd.Parameters.AddWithValue("#d24",0);
}
else
{
cmd.Parameters.AddWithValue("#d24",Convert.ToInt32(txtOtherDeductions.Text.Trim()));
}
if (txtIncomeTax.Text == "")
{
cmd.Parameters.AddWithValue("#d20",0);
}
else
{
cmd.Parameters.AddWithValue("#d20",Convert.ToInt32(txtIncomeTax.Text.Trim()));
}
cmd.Parameters.AddWithValue("#d29", chkActive.Text);
cmd.Parameters.AddWithValue("#d5",DOB.Text);
MemoryStream ms = new MemoryStream();
Bitmap bmpImage = new Bitmap(pictureBox1.Image);
bmpImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] data = ms.GetBuffer();
SqlParameter p = new SqlParameter("#d25", SqlDbType.Image);
p.Value = data;
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
d3 field can accept int but you are passing string`
default type of TextBox is string
you can fix this by converting to int
cmd.Parameters.AddWithValue("#d3",txtDepartment.Text);
to
cmd.Parameters.AddWithValue("#d3",Convert.ToInt(txtDepartment.Text));
You are passing few fields as string to DB datatype int :
cmd.Parameters.AddWithValue("#d28",txtID.Text);
cmd.Parameters.AddWithValue("#d3",txtDepartment.Text);
you should convert them to int prior passing it to db
cmd.Parameters.AddWithValue("#d28",Convert.ToInt32(txtID.Text.Trim()));
cmd.Parameters.AddWithValue("#d3",Convert.ToInt32(txtDepartment.Text.Trim()));
Just curious how come your txtDepartment be type of int , either you have to make a check whether there is string being passed or its an number . If it accepts only number you might have to check the value being passed to txtDepartment.Text and vice -versa.
I think the above answer is correct and he find the issues as well(Congrats). But the actual problem here is the Parameters.AddWithValue. It will not allows you to specify the type and will cause this kind of datatype conversion errors. So What i suggest you is, use Parameters.Add() instead for Parameters.AddWithValue() So that you can specify the type of expecting data and there by able to validate the input. you can see the below example(which help you to solve the issue as well):
cmd.Parameters.Add("#d28", SqlDbType.Int).Value = int.Parse(txtID.Text.Trim());
Where SqlDbType is an Enumeration which Specifies SQL Server-specific data type of a field, property, for use in a SqlParameter. int.TryParse() will be another best suggestion for you to perform error free conversion from string to integer.
Update : It seems The SP accepts values of different types, but you are giving all as string(.Text). This will create the same issue, So changing only "#d28" will not solve the issue, Try to read the attached link and make necessary changes in the code.

Specified cast is not valid when trying Convert.ToInt32(value)

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.

Categories