I am trying to execute a stored procedure with this declaration:
ALTER PROCEDURE [dbo].[getByName]
#firstName varchar,
#lastName varchar
AS
...
And I am calling in C# as follows:
public List<Person> GetPersonByName(string first, string last)
{
var people = new List<Person>();
var connString = ConfigurationManager.ConnectionStrings["MyDbConnString"].ConnectionString;
using (var conn = new SqlConnection(connString))
{
using (var cmd = new SqlCommand("dbo.getByName",conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#firstName", SqlDbType.VarChar, 50)).Value = first;
cmd.Parameters.Add(new SqlParameter("#lastName", SqlDbType.VarChar, 50)).Value = last;
conn.Open();
using (var reader = cmd.ExecuteReader())
{
people = ReadPeopleData(reader);
}
conn.Close();
}
}
return people;
}
But I just get back this error:
Procedure or function 'getByName' expects parameter '#firstName' which was not supplied.
Update:
ALTER PROCEDURE [dbo].[getEmployeesByName]
#firstName varchar(50),
#lastName varchar(50)
AS
...
and stating:
cmd.Parameters.Add(new SqlParameter("#firstName", SqlDbType.VarChar, 50)).Value
for both parameters, yet it continues to throw the exception.
I have seen this issue occur many, many times in two common scenarios:
The value being assigned to the parameter is null (or Nothing in VB.Net). This is the .Net null, not the DB null (DBNull.Value) and this happens most commonly with strings.
The parameter being created is associated with the wrong command object. This commonly occurs when you have multiple command objects in the same class with similar names.
Please double-check the code to ensure that the string variable is not set to null and that the parameter is being added to the correct command.
Update
Based on the full updated code that was posted, the likely issue is 1 above.
To circumvent this problem in your code, add the following at the top of the method:
if (first == null) {
first = "";
}
if (last == null) {
last = "";
}
Try this it will work:
SqlParameter[] sqlParams = new SqlParameter[] {
new SqlParameter("#UserName",(object)userName ?? DBNull.Value),
new SqlParameter("#Password",(object)password ?? DBNull.Value)
};
If parameter is NULL than replace it with DBNull Type using ?? Operator
Please add CommandaType to SQLCommand.
e.g: scmd.CommandType = CommandType.StoredProcedure;
Related
I have a web service in C#, I use it to consults from tables, but I want to create a WebMethod to call a stored procedure and get back multiples output parameters. I can execute it with output parameters, it doesn't work when I try to call it whit outputs parameters.
This is a sample, I want to get back more that 2 parameters.
Stored procedure:
CREATE OR REPLACE PROCEDURE O_CAPEREZ.GIO_SP (
VNOMBRE IN VARCHAR2,
SALUDO OUT VARCHAR2 )
AS
BEGIN
INSERT INTO G_PRUEBA_SP(NOMBRE)
VALUES (vNOMBRE);
SALUDO:= ('Hello: ' || vNOMBRE);
END;
And this is my code in the web service, when I execute it using output variables I get this error
[HYC00] [Oracle][ODBC]Optional feature not implemented
C# code:
[WebMethod]
public string AP_Data(string curp)
{
string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (OdbcConnection con = new OdbcConnection(constr))
{
OdbcCommand cmd = new OdbcCommand("{CALL GIO_SP(?,?)}", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#vNOMBRE", (curp));
cmd.Parameters.Add("#vNOMBRE", OdbcType.VarChar, 18);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Parameters["#SALUDO"].Direction = ParameterDirection.ReturnValue;
cmd.Connection.Close();
string ret = Convert.ToString(cmd.Parameters["#SALUDO"].Value);
return ret;
}
}
You have to add the parameter to the list even if you're not going to set a value there:
cmd.Parameters.Add("#SALUDO", OdbcType.VarChar, 18).Direction = ParameterDirection.Output;
I don't know the the Oracle flavor is different, but in SQL I use ParameterDirection.ReturnValue rather than ParameterDirection.Output.
here's how i do it in MS SQL server 2008 But notice the data type and the lenth of the variables your create must be the same in your table
the stored proc create code
USE DATABASE DATABASE_NAME
GO
CREATE PROC SP_METHOD
#ID_CATIGORY INT,
#NAME VARCHAR (50),
#DESCRIPTION VARCHAR (50)
AS
INSERT INTO TABLE_NAME
([ID_CAT]
,[NAME_PRODUCT]
,[DESC_PRODUCT]
)
VALUES
( #ID_CATIGORY
,#NAME
,#DESCRIPTION )
GO
in the c# code
// Create SqlConnection
SqlConnection conn= new SqlConnection(#"Server=server_name;
DataBase=your_data_base_name;Integrated Security=false;User
Id=user_id;Password=password");
// Open the Connection
if (sqlconnection.State != ConnectionState.Open)
{
conn= .Open();
}
// execute stored_procedure method don't change this
public void ExecuteCommand(string stored_procedure, SqlParameter[] param)
{
SqlCommand sqlcomd = new SqlCommand();
sqlcomd.CommandType = CommandType.StoredProcedure;
sqlcomd.CommandText = stored_procedure;
sqlcomd.Connection = sqlconnection;
if (param !=null)
{
sqlcomd.Parameters.AddRange(param);
}
sqlcomd.ExecuteNonQuery();
}
// close connection method
public void close_conn()
{
if (sqlconnection.State == ConnectionState.Open)
{
sqlconnection.Close();
}
}
// execute and retrieving data Method
public void Add_product(int ID_cat ,string Name_Product,string
Des_Product)
{
SqlParameter[] param = new SqlParameter[3];
param[0] = new SqlParameter("#ID_CAT", SqlDbType.Int);
param[0].Value = ID_cat;
param[1] = new SqlParameter("#NAME_PRODUCT", SqlDbType.VarChar, 50);
param[1].Value = Name_Product;
param[2] = new SqlParameter("#DESC_PRODUCT", SqlDbType.VarChar, 50);
param[2].Value = Des_Product;
ExecuteCommand("StoredProcedure_name", param);
close_conn();
}
and finally you can call this function
Add_product(Convert.ToInt32(ComboBox.SelectedValue),txt_name.Text,
txt_desc.Text);
if there is any part you don't understand lemme know
I've seen many ways to accomplish this.
One way is to Pipe Delimit your select statement in your stored procedure and then use "Value1|Value2".Split('|')[0] to get Value1.
You could also return a table instead of using multiple parameters
DataTable table = new DataTable();
DataAdapter adapter = new DataAdapter(cmd);
adapter.fill(table);
return table.Rows[0]["Greeting"] + table.Rows[0]["Name"];
In the second example you can return as many 'Parameters' as you want, but you will have to assign them to their rightful spots later in your code.
I've also seen an XML way to do this same feature but I won't provide the code here since I don't personally think it is a very good way to do it. The way I've seen done was adding a bunch of XML attributes to a parent tag, and then coming back later and finding the value of each tag later in the code.
In MYSQL it would go like this
CREATE PROCEDURE O_CAPEREZ.GIO_SP (
#vNOMBRE VARCHAR(50))
AS
BEGIN
INSERT INTO G_PRUEBA_SP(NOMBRE)
VALUES (#vNOMBRE);
select 'Hola' as Greeting, #vNOMBRE as Name
END
Also note what Marc_s commented
You need to set the .Direction of the parameter BEFORE making the call to .ExecuteNonQuery()
I am getting this error when I try to call my stored procedure form code behind in my website. I have been stuck for quite a while now, as I do not know anywhere I am converting or declaring a value as an integer. This is my SQL statement:
create procedure GetRepPhoneID
#Rep nvarchar(100),
#phoneID nvarchar(100) output
as
set #phoneID = (select concat(CustomerRepPh, '~', cast(RepID as nvarchar(100))) as 'PhoneAndID'
from Reps
where CustomerRep=#Rep)
return #phoneID
go
Then from my c# code behind I am trying to call the stored procedure:
public static string GetRepPhone(string Rep)
{
string Connection = WebConfigurationManager.ConnectionStrings["JDC_DatabaseConnectionString"].ConnectionString;
SqlConnection sqlConnection = new SqlConnection(Connection);
//This funciton will take all of the values and create them.
try
{
sqlConnection.Open();
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
SqlCommand cmd = new SqlCommand();
cmd.Connection = sqlConnection;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetRepPhoneID"; //getting the procedure created in SQL.
SqlParameter CustomerParam = new SqlParameter();
CustomerParam.ParameterName = "Rep";
CustomerParam.SqlDbType = SqlDbType.NVarChar;
CustomerParam.Value = Rep;
CustomerParam.Direction = ParameterDirection.Input;
//We are using an output parameter not a return one because it is a string.
SqlParameter ReturnParam = new SqlParameter("phoneID", SqlDbType.NVarChar, 100);
ReturnParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(CustomerParam);
cmd.Parameters.Add(ReturnParam);
cmd.ExecuteNonQuery();
sqlConnection.Close();
return ReturnParam.Value.ToString();
}
I am doing the same thing multiple times in my code, but they all return integers so there has been no error thrown so I know it should work. The error is being thrown on the cmd.ExecuteNonQuery() line. The exact error is:
Conversion failed when converting the nvarchar value '(111)222-6666~29' to data type int.
I understand that I cannot convert that string to an integer, but I do not see anywhere in my code I am declaring an integer, or I am trying to convert.
Any help will be appreciated. Thanks.
You are confusing a RETURN value for an OUTPUT parameter. A RETURN is an optional status code of type INT. Declare another parameter as OUTPUT.
Meaning, this is invalid in the Stored Procedure:
return #phoneID
Instead, add #phoneID nvarchar(100) OUTPUT to the parameter list and remove the DECLARE #PhoneID:
CREATE PROCEDURE GetRepPhoneID
(
#Rep NVARCHAR(100),
#phoneID NVARCHAR(100) OUTPUT
)
AS
SET NOCOUNT ON;
SELECT #phoneID = concat(CustomerRepPh, '~', RepID)
FROM Reps
WHERE CustomerRep = #Rep;
The above represents the entire proc. You don't need the RETURN or the SET.
Then in the C# code, you need to change how that parameter is specified:
SqlParameter ReturnParam = new SqlParameter("phoneID", SqlDbType.NVarChar, 100);
ReturnParam.Direction = ParameterDirection.Output;
Then remove this line as it is not needed since the value of the parameter will remain after the connection is closed:
string PhoneAndID = cmd.Parameters[1].Value.ToString();
And change the return to be:
return ReturnParam.Value.ToString();
Lastly, you probably need to update the declaration of the input param as follows:
SqlParameter CustomerParam = new SqlParameter("Rep", SqlDbType.NVarChar, 100);
CustomerParam.Value = Rep;
CustomerParam.Direction = ParameterDirection.Input;
using (SqlCommand cmd = new SqlCommand())
{
DataTable dt = new DataTable();
cmd.CommandText = p;
cmd.CommandType = CommandType.Text;
SqlConnection con = new SqlConnection("--");
cmd.Connection = con;
cmd.Connection.Open();
foreach (var parameter in filters)
{
var type = parameter.Value.GetType();
var param = new SqlParameter(parameter.Id, parameter.Value);
param.Direction = ParameterDirection.Input;
param.Value = parameter.Value;
cmd.Parameters.Add(param);
}
dt.Load(cmd.ExecuteReader());
cmd.Connection.Close();
return dt;
}
Here is my code.
Variable "p" is my sqlQuery string.
Variable "filters" is my parameter list.
For example: parameter.Id = "#offerId" (as string) and parameter.Value = 1230 (as Integer)
Also my query is like that : "select * from Offers where ID = #offerID and IsActive = #isActive"
when pass into cmd.ExecuteReader(), in IntelliTrace shows my query like that:
--The data may be truncated and may not represent the query that was run on the server
USE [DB];
GO
--Type and value data was not available for the following variables. Their values have been set to defaults.
DECLARE #offerID AS SQL_VARIANT;
DECLARE #isActive AS SQL_VARIANT;
SET #offerID = NULL;
SET #isActive = NULL;
select * from Offers where ID = #offerID and IsActive = #isActive
We tried lots of method for set. But always variables set null.
IntelliTrace currently only supports this kind of type information for log files from MMA scenarios. In your scenario, the type information from SqlParameter isn't collected; as a result all the variables in the query default to SQL_VARIANT with null values.
Using your code on Visual Studio 2010 and SQL Server 2008 I tried to reproduce your scenario (or at least what I thought your scenario was as you weren't very specific).
I created these tables: Q25682067 using int for the offer id and bit for the 'isActive' field; and Q25682067_Offers with sql_variant for each field, as suggested by your post.
CREATE TABLE [Q25682067]([ID] [int] NOT NULL, [IsActive] [bit] NOT NULL) ON [PRIMARY]
CREATE TABLE [Q25682067_Offers]([ID] [sql_variant] NOT NULL,[IsActive] [sql_variant] NOT NULL ) ON [PRIMARY]
Data pairs (1,false) and (1,true) added to each table.
Now considering your filters are something like:
var filters = new Parameter[] {
new Parameter() {Id="#offerID ", Value=1},
new Parameter() {Id="#isActive", Value=false}
};
where a Parameter might very swiftly be (without any consideration to OOP practices):
internal class Parameter
{
public string Id;
public object Value;
}
Now, this populates the data table:
cmd.CommandText = "select * from Q25682067 where ID = #offerID and IsActive = #isActive";
this does not:
cmd.CommandText = "select * from Q25682067_Offers where ID = #offerID and IsActive = #isActive";
Using the SqlParameter constructor like that binds your parameters to SqlDbType.Int and SqlDbType.Bit instead of SqlDbType.Variant, which seems to be your weapon of choice. That's why your code works with the first table definition, and not the second.
I have following code for specifying parameters for SQL query. I am getting following exception when I use Code 1; but works fine when I use Code 2. In Code 2 we have a check for null and hence a if..else block.
Exception:
The parameterized query '(#application_ex_id nvarchar(4000))SELECT E.application_ex_id A' expects the parameter '#application_ex_id', which was not supplied.
Code 1:
command.Parameters.AddWithValue("#application_ex_id", logSearch.LogID);
Code 2:
if (logSearch.LogID != null)
{
command.Parameters.AddWithValue("#application_ex_id", logSearch.LogID);
}
else
{
command.Parameters.AddWithValue("#application_ex_id", DBNull.Value );
}
QUESTION
Can you please explain why it is unable to take NULL from logSearch.LogID value in Code 1 (but able to accept DBNull)?
Is there a better code to handle this?
Reference:
Assign null to a SqlParameter
Datatype returned varies based on data in table
Conversion error from database smallint into C# nullable int
What is the point of DBNull?
CODE
public Collection<Log> GetLogs(LogSearch logSearch)
{
Collection<Log> logs = new Collection<Log>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string commandText = #"SELECT *
FROM Application_Ex E
WHERE (E.application_ex_id = #application_ex_id OR #application_ex_id IS NULL)";
using (SqlCommand command = new SqlCommand(commandText, connection))
{
command.CommandType = System.Data.CommandType.Text;
//Parameter value setting
//command.Parameters.AddWithValue("#application_ex_id", logSearch.LogID);
if (logSearch.LogID != null)
{
command.Parameters.AddWithValue("#application_ex_id", logSearch.LogID);
}
else
{
command.Parameters.AddWithValue("#application_ex_id", DBNull.Value );
}
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
Collection<Object> entityList = new Collection<Object>();
entityList.Add(new Log());
ArrayList records = EntityDataMappingHelper.SelectRecords(entityList, reader);
for (int i = 0; i < records.Count; i++)
{
Log log = new Log();
Dictionary<string, object> currentRecord = (Dictionary<string, object>)records[i];
EntityDataMappingHelper.FillEntityFromRecord(log, currentRecord);
logs.Add(log);
}
}
//reader.Close();
}
}
}
return logs;
}
Annoying, isn't it.
You can use:
command.Parameters.AddWithValue("#application_ex_id",
((object)logSearch.LogID) ?? DBNull.Value);
Or alternatively, use a tool like "dapper", which will do all that messing for you.
For example:
var data = conn.Query<SomeType>(commandText,
new { application_ex_id = logSearch.LogID }).ToList();
I'm tempted to add a method to dapper to get the IDataReader... not really sure yet whether it is a good idea.
I find it easier to just write an extension method for the SqlParameterCollection that handles null values:
public static SqlParameter AddWithNullableValue(
this SqlParameterCollection collection,
string parameterName,
object value)
{
if(value == null)
return collection.AddWithValue(parameterName, DBNull.Value);
else
return collection.AddWithValue(parameterName, value);
}
Then you just call it like:
sqlCommand.Parameters.AddWithNullableValue(key, value);
Just in case you're doing this while calling a stored procedure: I think it's easier to read if you declare a default value on the parameter and add it only when necessary.
SQL:
DECLARE PROCEDURE myprocedure
#myparameter [int] = NULL
AS BEGIN
C#:
int? myvalue = initMyValue();
if (myvalue.hasValue) cmd.Parameters.AddWithValue("myparamater", myvalue);
some problem, allowed with Necessarily set SQLDbType
command.Parameters.Add("#Name", SqlDbType.NVarChar);
command.Parameters.Value=DBNull.Value
where SqlDbType.NVarChar you type. Necessarily set SQL type.
I am sending ID as outparameter but its giving error
System.Data.SqlClient.SqlException: Procedure or function
'usp_ClientHistoryItem' expects parameter '#ID', which was not
supplied.
Code
using (SqlCommand cmd = new SqlCommand("dbo.usp_ClientHistoryItem", conn))
{
SqlParameter parameterID = new SqlParameter("#ID", oReservation.Id);
parameterID.Direction = ParameterDirection.Output;
cmd.Parameters.Add(parameterID);
cmd.Parameters.Add(new SqlParameter("#PhoneNo", oReservation.ClientPhone));
cmd.Parameters.Add(new SqlParameter("#UserId", oReservation.UserID));
cmd.Parameters.Add(new SqlParameter("#Description", oReservation.Description));
cmd.Parameters.Add(new SqlParameter("#TestId", oReservation.TestId));
cmd.Parameters.Add(new SqlParameter("#StartDate", oReservation.StartDate));
cmd.ExecuteNonQuery();
returnValue = Convert.ToInt32(cmd.Parameters["#ID"].Value);
return returnValue;
}
You seem to be calling a stored procedure - yet you've never defined your SqlCommand to be a stored procedure:
using (SqlCommand cmd = new SqlCommand("dbo.usp_ClientHistoryItem", conn))
{
cmd.CommandType = CommandType.StoredProcedure; // add this line to tell ADO.NET it's a stored procedure!!
If you forget that line, then ADO.NET will try to interpret your stuff as an ad-hoc SQL statement....
this one solve my problem
may be it may helpful
cmd.CommandType = CommandType.StoredProcedure;
Your ID parameter in the stored procedure must be set as OUTPUT parameter. You are just setting it in code not in stored procedure.
Hy guys.
You have to set the property CommandType for the Command to StoredProcedure if that's the case. Otherwise it woun't detect the parameters.
One other reason this error is thrown is when the variable names don't match in your stored procedure and code because the code fails to find the parameter to which the value must be passed. Make sure they match:
Stored procedure:
create procedure getEmployee
#ID
as
Begin
select *
from emp
where id = #ID
End
Code:
SqlParameter p = new SqlParameter("#ID", id);
cmd.Parameter.Add(p);
The parameter #ID must match in both code and stored procedure
If you use dapper, you can use this construction
int id = 1;
var parameters = new DynamicParameters();
parameters.Add("#id", id, DbType.Int32, ParameterDirection.Input);
string sqlQuery = "[dbo].[SomeStoredProcedure]";
using (IDbConnection db = new SqlConnection(ConnectionString))
{
var result = await db.QueryAsync<SpResult>(sqlQuery, parameters, commandType: CommandType.StoredProcedure);
}