DbContext ExecuteSqlRaw missing parameters error - c#

I have this code for executing stored procedure:
var result = await DbContext.Database.ExecuteSqlRawAsync(
"Get_FlightBooking #BookingReferenceNumber, #BM_BKDTFOM, #BM_BKDTTO, #User_Id",
new SqlParameter("#BookingReferenceNumber", model.BookingId == string.Empty ? null : model.BookingId),
new SqlParameter("#BM_BKDTFOM", model.FromDt == string.Empty ? null : model.FromDt),
new SqlParameter("#BM_BKDTTO", model.FromDt == string.Empty ? null : model.FromDt),
new SqlParameter("#User_Id", model.UserId));
This is the stored procedure:
ALTER Proc [dbo].[Get_FlightBooking]
(
#BookingReferenceNumber VARCHAR(50)=NULL,
#BM_BKDTFOM VARCHAR(50)=NULL,
#BM_BKDTTO VARCHAR(50)=NULL,
#User_Id bigint=null
)
as
begin
SELECT distinct BookingID,
BookingReferenceNumber,
Sector,
AirlineCode,
AirlineName,
FROM dbo.Flights AS fb
WHERE (fb.BookingReferenceNumber=#BookingReferenceNumber OR #BookingReferenceNumber IS NULL)
AND((CAST(fb.BookingDate AS DATE)>= CAST(#BM_BKDTFOM AS DATE) OR #BM_BKDTFOM IS NULL) AND (CAST(fb.BookingDate AS DATE)<=CAST(#BM_BKDTTO AS DATE) OR #BM_BKDTTO IS NULL))
AND (fb.UserId=#User_Id or #User_Id=1)
END
Is anyone seeing something wrong in the way how the stored procedure is being executed? When calling the C# code I'm getting this error:
The parameterized query '(#BookingReferenceNumber
nvarchar(4000),#BM_BKDTFOM nvarchar(400' expects the parameter
'#BookingReferenceNumber', which was not supplied.
Any idea what can be wrong?

You need to use DBNull.Value and not null
var result = await DbContext.Database.ExecuteSqlRawAsync(
"UspGet_FlightBooking #BookingReferenceNumber, #BM_BKDTFOM, #BM_BKDTTO, #User_Id",
new SqlParameter("#BookingReferenceNumber", string.IsNullOrWhiteSpace(model.BookingId) ? DNNull.Value : model.BookingId),
new SqlParameter("#BM_BKDTFOM", string.IsNullOrWhiteSpace(model.FromDt) ? DNNull.Value : model.FromDt),
new SqlParameter("#BM_BKDTTO", string.IsNullOrWhiteSpace(model.FromDt) ? DNNull.Value : model.FromDt),
new SqlParameter("#User_Id", model.UserId));
If you cant use C# 9.0 maybe try initialising your SqlParameters like this:
new SqlParameter("#BookingReferenceNumber", System.Data.SqlDbType.NVarChar, 4000)
{ Value = string.IsNullOrWhiteSpace(model.BookingId) ? (object)DBNull.Value : model.BookingId }

Related

EF6 SqlQuery with named parameters

I have a stored procedure accepting a few paramaters but I can't figure out the right syntax. According to varios sources, the following should work:
var results = base.Context.Database.SqlQuery<UserSummary>("exec FindPatients forenames = #forenames, surname = #surname",
new SqlParameter("#forenames", string.IsNullOrWhiteSpace(forenames) ? (object)DBNull.Value : forenames),
new SqlParameter("#surname", string.IsNullOrWhiteSpace(surname) ? (object)DBNull.Value : surname));
When .ToList() is called, I get an SqlException: Incorrect syntax near '='.
I've tried removing the exec:
var results = base.Context.Database.SqlQuery<UserSummary>("FindPatients #forenames, #surname",
new SqlParameter("#forenames", string.IsNullOrWhiteSpace(forenames) ? (object)DBNull.Value : forenames),
new SqlParameter("#surname", string.IsNullOrWhiteSpace(surname) ? (object)DBNull.Value : surname));
Which results in The SqlParameter is already contained by another SqlParameterCollection
I don't want to use numbered parameters and pass {1}, {2} etc in to the sproc as I need 10 or so parameters and it's a maintenance nightmare. Am I missing something?

Application generating Error:Must Declare Scalar Variable In Web Api 2. Also, practices regarding the code in WebApi2 and debugging Controller method

I asked a lot in here, as I am new to MVC, WebApi and RestService.
So, I am working with an application where StoredProcedure is being called inside Controller, but getting Error :
Must Declare Scalar Variable #empid
Code is below :
[HttpGet]
[Route("~/api/Login/{EmpID}/{pwd}")]
public IHttpActionResult ValidateLoginDetails(string EmpID, string pwd)
{
int a=0;
if (EmpID == null)
EmpID = "";
else a = Int32.Parse(EmpID);
if (pwd == null)
pwd = "";
var val = new SqlParameter()
{ParameterName="#val",Direction=ParameterDirection.Output,SqlDbType=SqlDbType.Int};
var e = new SqlParameter("#empid", SqlDbType.Int) ;
e.Value = a;
//User.Identity.Name;
var y = new SqlParameter("#pwd", SqlDbType.VarChar);
y.Value = pwd;
using (var x = new DB_BgCheckEntities())
{
var retVal = x.Database.SqlQuery<IEnumerable<int>>
("Exec proc_Bgcheck_login #empid,#pwd,#val out", e, y, val);
// var ret = retVal.Single();
//foreach(var ab in retVal)
//{
// Console.WriteLine(ab.ToList());
//}
//retVal.ToList();
x.Database.ExecuteSqlCommand("Exec proc_Bgcheck_login #eid,#pwd,#val out", e, y, val);
if ((int)val.Value == 1)
{
return Ok(1);
}
else return NotFound();
}
}
Below statement is doing my work, but I am not getting why the dbcontext is not working
x.Database.ExecuteSqlCommand("Exec proc_Bgcheck_login #eid,#pwd,#val out", e, y, val);
Stored Proc :
CREATE PROCEDURE proc_Bgcheck_login
(
#emp_no int,
#pwd varchar(255),
#val int output
)as
BEGIN
SET #val=0;
DECLARE #count int;
SELECT #count=COUNT(*) FROM tbl_User_Login where [Emp No]=#emp_no and [Password]=#pwd;
IF (#count = 1)
BEGIN
SET #val=1;
RETURN #val;
END
ELSE
RETURN #val;
END
GO
Few questions, I need to ask :
Is it good practice, to call StoredProc inside GetMethod, like I did.
How to implement the DTO(Data Transfer Object) for this method? I googled down, but didn't got the concept for that.
Debugging method inside Controller, how to do that line by line ?
PS : For the error, I went through different sites and threads of StackOverflow, but none resolved my solution.
The error :
Must declare Scalar Variable #empid is resolved .
As mentioned by #amit, I haven't passed the parameters for the #empid and #pwd.
So, the correct way to pass the parameter was :
var retVal = dbcontext.Database.SqlQuery<tbl_User_Login>
("Exec proc_Bgcheck_login #empid,#pwd,#val ",e,y, val).ToList();
Thanks.

How to send a Null value in xml string

The RefNo column in SQL Server table is of datatype bigint, and can accept Nulls.
I am saving multiple records via xml using c#. The code works good, but for a few records, the RefNo has to be null, and it is saving as 0 even when I comment the 'else' part in stringbuilder.
SQL:
ALTER PROCEDURE SaveActivity
#XMLData xml
AS
BEGIN
IF #XMLData IS NOT NULL
BEGIN
CREATE TABLE #Temp(
ActivityId uniqueidentifier,
RefNo int,
Notes nvarchar(500)
);
INSERT INTO tblActivityDetails(ActivityId,RefNo,Notes)
SELECT
detail.query('ActivityId').value('.','uniqueidentifier') as ActivityId,
detail.query('RefNo').value('.','int') as RefNo,
detail.query('Notes').value('.','nvarchar(500)') as Notes
FROM
#XMLData.nodes('/details/detail') AS xmlData(detail)
END
END
C#:
StringBuilder sb = new StringBuilder();
sb.AppendLine("<?xml version=\"1.0\"?>");
sb.AppendLine("<details>")
foreach(GridViewRow gr in gvActivity.Rows)
{
HiddenField hdRefNo = (HiddenField)gr.FindControl("hdRefNo");
HiddenField hdNotes = (HiddenField)gr.FindControl("hdNotes");
string sRefNo = hdRefNo.value.ToString()=="0" ? null :
hdRefNo.value.ToString();
sb.AppendLine("<detail>");
sb.AppendLine("<ActivityId>"+ gActivityId.ToString() + "</ActivityId>");
if(sRefNo!="0")
sb.AppendLine("<RefNo>"+ sRefNo + "</RefNo>");
else
sb.AppendLine("<RefNo></RefNo>");
sb.AppendLine("<Notes>"+ hdNotes.value.ToString() + "</Notes>");
sb.AppendLine("</detail>");
}
sb.AppendLine("</details>")
You don't need to use query() when fetching values. Use values() directly and you will get NULL if the RefNo node is missing.
detail.value('(RefNo/text())[1]','int') as RefNo
Try using "" instead of null in
string sRefNo = hdRefNo.value.ToString()=="0" ? null :
hdRefNo.value.ToString();
like
string sRefNo = hdRefNo.value.ToString()=="0" ? "":
hdRefNo.value.ToString();
and remove if else part and just keep the statement
sb.AppendLine("<RefNo>"+ sRefNo + "</RefNo>");
In this line
string sRefNo = hdRefNo.value.ToString()=="0" ? null :
hdRefNo.value.ToString();
your checking string and if it equals "0" that assign null, so when you after try checking
if(sRefNo!="0") // this condition always true
sb.AppendLine("<RefNo>"+ sRefNo + "</RefNo>");
else
sb.AppendLine("<RefNo></RefNo>");
Possibly if you change condition to !string.IsNullOrEmpty(sRefNo) it will be work as expected
When you try get int field and in xml it don't set, then here
....
detail.query('RefNo').value('.','int') as RefNo,
....
will be return default value, i.e. 0
for solving you can try use number() function like this
....
detail.query('RefNo').value('number(.)','int') as RefNo,
....

Passing DBNull.Value and Empty textbox value to database [duplicate]

This question already has answers here:
How do I Parameterize a null string with DBNull.Value clearly and quickly
(8 answers)
Closed 8 years ago.
I have some textboxes on my page which can be empty because they are optional and I have this DAL code
parameters.Add(new SqlParameter("#FirstName", FirstName));
parameters.Add(new SqlParameter("#LastName", LastName));
parameters.Add(new SqlParameter("#DisplayName", DisplayName));
parameters.Add(new SqlParameter("#BirthDate", BirthDate));
parameters.Add(new SqlParameter("#Gender", Gender));
Any of those fields can be empty. The problem is when they are empty I receive Procedure XXX requires #FirstName which was not supplied
Then I changed my code to
parameters.Add(new SqlParameter("#FirstName", String.IsNullOrEmpty(FirstName) ? DBNull.Value : (object)FirstName));
parameters.Add(new SqlParameter("#LastName", String.IsNullOrEmpty(LastName) ? DBNull.Value : (object) LastName));
parameters.Add(new SqlParameter("#DisplayName", String.IsNullOrEmpty(DisplayName) ? DBNull.Value : (object) DisplayName));
parameters.Add(new SqlParameter("#BirthDate", BirthDate.HasValue ? (object)BirthDate.Value : DBNull.Value));
parameters.Add(new SqlParameter("#Gender", String.IsNullOrEmpty(Gender) ? DBNull.Value : (object) Gender));
But this looks messy to me especially the casting to object because ternary statement requires both value to be the same type.
Why is empty string or null string not treated NULL in the database? If I have to convert this to DBNull.Value is there a cleaner way? Saving the value as empty string in the database could have helped but query for NULL in the database will get messy too
Please give your advice on common practices or something close to that.
First, there are 2 more handy overloads:
command.Parameters.Add("#name").Value = value;
or
command.Parameters.AddWithValue("#name", value);
Personally I use the following extension method:
public static object DbNullIfNull(this object obj)
{
return obj != null ? obj : DBNull.Value;
}
command.Parameters.AddWithValue("#name", value.DbNullIfNull());
or
public static object DbNullIfNullOrEmpty(this string str)
{
return !String.IsNullOrEmpty(str) ? str : (object)DBNull.Value;
}
A little re-factoring might make code less messy. Try this
dbParams.Add(SetDBNullIfEmpty("#FirstName", FirstName));
dbParams.Add(SetDBNullIfEmpty("#LastName", LastName));
dbParams.Add(SetDBNullIfEmpty("#DisplayName", DisplayName));
dbParams.Add(SetDBNullIfEmpty("#BirthDate", BirthDate));
dbParams.Add(SetDBNullIfEmpty("#Gender", Gender));
private SqlParameter SetDBNullIfEmpty(string parmName, string parmValue)
{
return new SqlParameter(parmName, String.IsNullOrEmpty(parmValue) ? DBNull.Value : (object)parmValue));
}
You can default the parameters in the stored procedure, making them optional.
create procedure XXX
(
#FirstName nvarchar(50) = null,
#LastName nvarchar(50) = null,
...
)

Update a float to null?

I have this stored Procedure in MS SQL2008 (C#)
ALTER PROCEDURE UpdateProducts
#ProductID INT, #Name nvarchar(50), #Length Float
AS
UPDATE Product
SET Name = #Name, Length = #Length
WHERE (ProductID = #ProductID)
Length are in some cases "" (nothing). But when "" is inserted the value 0 is inserted instead. I want the value to be null. How can I do that? This did not work:
if (Length == "")
{
Length = null;
}
Set the defaults to NULL in the proc and you dont have to explicity pass NULL to a proc.
CREATE PROC ..dbo.Proc ( #param1 int =NULL, #param2 varchar(40) = NULL ,etc)
Also, if you have to send NULL from your app you would use DBNull.Value
Try DBNull.Value:
if (Size == "")
{
Size = DBNull.Value;
}
and make sure your database column is nullable.
Use NULLIF
UPDATE Product
SET Name = #Name, Length = NULLIF(#Length, '')
WHERE (ProductID = #ProductID)
Empty string is implicitly cast to 0 for float and int. decimal gives an error
Empty string and NULL are different
Edit: this deals with unclean input, so you don't have to worry about it...

Categories