Attempted (non-working) solution included below.
I have an sql function called get_parameter which looks in a table for a given string and returns the associated string:
declare #str varchar(20);
set #str = dbo.get_parameter('filecount')
print #str
It works! I run this and it prints out exactly what it should print. In this case, the parameter is the string '44'.
Now I want to run a C# CLR. But I want the CLR to be able to look up the parameter that it needs.
[SqlFunction(DataAccess = DataAccessKind.Read)]
public static string Import_TestFunc()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
SqlCommand command = new SqlCommand();
command.Connection = conn;
conn.Open();
// Find out how many files DSAMS processing requires.
command.CommandText = #"EXEC get_parameter 'filecount' ";
string cnt = (string)command.ExecuteScalar();
if (String.IsNullOrEmpty(cnt))
{
return "'cnt' not found."; // error return code. can't find this parameter.
}
return cnt;
}
}
However, this does not work. It constantly thinks the value for cnt is null (or empty) when it returns from get_parameter.
As requested, the code for get_parameter
ALTER FUNCTION [dbo].[get_parameter]
(
#SelectedParameterName nvarchar(max)
)
RETURNS nvarchar(max)
AS
BEGIN
DECLARE #result nvarchar(max);
SET #result = (SELECT ParameterValue from Parameters WHERE ParameterName = #SelectedParameterName);
RETURN isnull(#result,'');
END
I have tried the solution as per Mike Dinescu below, but it problem is that the call to ExecuteScalar() still returns a null. I did try to change to CommandType.Text and in that case I get the following interesting message:
A .NET Framework error occurred during execution of user-defined routine or aggregate "Import_TestFunc":
System.Data.SqlClient.SqlException: Procedure or function 'get_parameter' expects parameter '#SelectedParameterName', which was not supplied.
This is interesting, because I'm looking right at where it adds the parameter #SelectedParameterName.
command.Parameters.Add(new SqlParameter("#SelectedParameterName", SqlDbType.NVarChar )).Value = "filecount";
If you want to execute a user-defined function, or stored procedure from .NET, you should set the CommandType to CommandType.StoredProcedure, and add the needed parameters to the command object before executing the command.
command.CommandType = CommandType.StoredProcedure;
command.CommandText = #"dbo.get_parameter";
// here you add the paramters needed for your procedure/function
// in your case it will be just one (make sure you add the correct name for you function)
command.Parameters.Add(new SqlParamter("SelectedParameterName", SqlDbType.NVarChar));
command.Prepare();
command.Parameters[0].Value = "filecount";
string cnt = (string)command.ExecuteScalar();
Related
I have this code in C# and I want to use a string sReturn as output parameter in my code.
var sReturn = new SqlParameter();
sReturn.ParameterName = "#Return";
sReturn.SqlDbType = SqlDbType.VarChar;
sReturn.Size = 300;
sReturn.Direction = ParameterDirection.Output;
string query = "exec #Return = sqlServerProcedure #id, #dateBegin, #dateEnd";
_context.Database.CommandTimeout = timeout;
_context.Database.ExecuteSqlCommand
(query, sReturn,
new SqlParameter("#id", id),
new SqlParameter("#dateBegin", dateBegin),
new SqlParameter("#dateEnd", dateEnd) );
return sReturn.Value;
sReturn is always returning 0.
Procedure is something like this:
CREATE PROCEDURE [dbo].sqlServerProcedure
(#dateBegin DATETIME,
#dateEnd DATETIME,
#id NUMERIC)
AS
BEGIN
SELECT 'some random message'
END
Why is it always returning 0?
You really don't need to declare #return parameter, if you are expecting a single value from procedure, use ExecuteScalar() method of SQL command.
Also you can use stored procedure type instead of inline SQL query. Your ADO.net code will look like below, no changes in stored procedure.
_context.Database.Connection.Open();
var cmd = _context.Database.Connection.CreateCommand();
cmd.CommandTimeout = timeout;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sqlServerProcedure";
cmd.Parameters.Add(new SqlParameter("#id", id));
cmd.Parameters.Add(new SqlParameter("#dateBegin", dateBegin));
cmd.Parameters.Add(new SqlParameter("#dateEnd", dateEnd));
var result = (string)cmd.ExecuteScalar();
The error is in the SQL Server procedure and the calling of it in ExecuteSqlCommand.
You have to do this in C#:
string query = "exec sqlServerProcedure #id, #dateBegin, #dateEnd, #Return OUTPUT";
In SQL Server:
CREATE PROCEDURE [dbo].sqlServerProcedure
(#dateBegin DATETIME,
#dateEnd DATETIME,
#id NUMERIC,
#Return VARCHAR(300) OUTPUT)
The documentation for EXECUTE (Transact-SQL) contains the following:
#return_status
Is an optional integer variable that stores the return status of a module. This variable must be declared in the batch, stored procedure, or function before it is used in an EXECUTE statement.
When used to invoke a scalar-valued user-defined function, the #return_status variable can be of any scalar data type.
Since you are invoking a stored procedure (not scalar-valued function), the return value is 0 (success) converted to string.
If you were using ADO.NET, then you could use ExecuteScalar as mentioned in another answer. However EF6 ExecuteSqlCommand method is equivalent of the ADO.NET ExecuteNonQuery and cannot be used to retrieve the returned single row single column record set.
The easiest way to execute your stored procedure and get the desired string result in EF6 is to use the combination of EF SqlQuery<string> method and LINQ FirstOrDefault:
var returnValue = _context.Database
.SqlQuery<string>("sqlServerProcedure #p0, #p1, #p2", dateBegin, dateEnd, id)
.FirstOrDefault();
I have a stored procedure that has a parameter called UserName and in my code behind I have a SqlCommand object that I add the parameters to with the Add method. But for some reason when the command object tries to run the ExecuteReader method, it throws an exception. I am totally at a loss and have no idea why it's not recognizing the parameter. Before the ExecuteReader method is run I have a break point set so I can confirm the command object does contain the parameters being set, which is true. I know the stored procedure does return the correct data when the parameters are not added to the command object, but are hard coded in the actual stored procedure. Below is the exception message that is given in the catch block. I will also paste my code and first part of stored procedure. I would greatly appreciate any help in this issue, seeing that I have tried many different approaches to no avail. Thanks in advance.
Exception Message
Procedure or function 'someStoredProcedure' expects parameter '#UserName', which was not supplied.
Code Behind
private DataTable GetLossMitData(string code, DateTime? start, DateTime? end)
{
DataTable results = new DataTable();
string connectionString = ConfigurationManager.ConnectionStrings["asdf"].ConnectionString;
string userName = String.Empty;
try
{
using (SPSite site = new SPSite(ConfigurationManager.AppSettings["someName"]))
{
using (SPWeb web = site.OpenWeb())
{
userName = web.CurrentUser.Email.ToString();
}
}
using (SqlConnection connection1 = new SqlConnection(connectionString))
{
connection1.Open();
using (SqlCommand command1 = new SqlCommand("someStoredProcedure", connection1))
{
command1.Parameters.Add(new SqlParameter("#UserName", userName));
command1.Parameters.Add(new SqlParameter("#ProductCode", code));
SqlDataReader dr = command1.ExecuteReader(CommandBehavior.CloseConnection);
results.Load(dr);
}
connection1.Close();
}
}
catch (Exception ex)
{
}
return results;
}
Stored Procedure
#UserName nvarchar(256),
#ProductCode nvarchar(256),
#StartDate nvarchar(256) = '1/1/1900',
#EndDate nvarchar(256) = '12/30/2012'
AS
BEGIN
SET NOCOUNT ON;
Declare #UserID int
Select #UserID = Users.UserID
from Users
where Users.Email = #UserName
Try making sure that the command type is set to stored procedure.
mycommand.CommandType = System.Data.CommandType.StoredProcedure;
You will get this exception if the value of your 'userName' variable is null
If null is valid, then pass 'DBNull.Value' to the db instead:
command1.Parameters.Add(new SqlParameter("#UserName", (userName ?? DBNull.Value));
Command1.CommandType = System.Data.CommandType.StoredProcedure
This will force the ExecuteReader to perform the exec instead of just trying it as a flat command.
By default, the CommandText property needs to contain a complete SQL command, not just the name of the stored procedure.
You can change this by to set the SqlCommand's CommandType property to StoredProcedure.
Alternatively, you could explicitly pass the parameters, by changing the CommandText to "someStoredProcedure #UserName, #ProductCode"; this is a complete SQL statement and will work with the default CommandType of Text.
EDIT: I just tried it, and the only way to get that error message without setting CommandType to StoredProcedure (which he did not do) is if CommandText is EXEC someStoredProcedure. Passing a null parameter gives a different error.
I am fairly new to C# and I'm trying to set up call to a stored procedure in my database which takes one parameter.
I get the error "Procedure or function 'SP_getName' expects parameter '#username', which was not supplied. "
My Stored procedure works ok when I supply it with the parameter and I run it via SQL management studio.
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[SP_getName]
#username = 'bob101'
SELECT 'Return Value' = #return_value
GO
However when I try and call it the error is with how I'm passing the parameter in, but I can't spot what the issue is.
//create a sql command object to hold the results of the query
SqlCommand cmd = new SqlCommand();
//and a reader to process the results
SqlDataReader reader;
//Instantiate return string
string returnValue = null;
//execute the stored procedure to return the results
cmd.CommandText = "SP_getName";
//set up the parameters for the stored procedure
cmd.Parameters.Add("#username", SqlDbType.NVarChar).Value = "bob101";
cmd.CommandType = CommandType.Text;
cmd.Connection = this.Connection;
// then call the reader to process the results
reader = cmd.ExecuteReader();
Any help in spotting my error would be greatly appreciated!
I've also tried looking at these two posts, but I haven't had any luck:
Stored procedure or function expects parameter which is not supplied
Procedure or function expects parameter, which was not supplied
Thanks!
You have stated:
cmd.CommandType = CommandType.Text;
Therefore you are simply executing:
SP_getName
Which works because it is the first statement in the batch, so you can call the procedure without EXECUTE, but you aren't actually including the parameter. Change it to
cmd.CommandType = CommandType.StoredProcedure;
Or you can change your CommandText to:
EXECUTE SP_getName #username;
As a side note you should Avoid using the prefix 'sp_' for your stored procedures
And a further side note would be to use using with IDisposable objects to ensure they are disposed of correctly:
using (var connection = new SqlConnection("ConnectionString"))
using (var cmd = new new SqlCommand("SP_getName", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#username", SqlDbType.NVarChar).Value = "bob101";
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// Do something
}
}
}
I had this problem, but it wasn't about parameter name of Command Type.
My problem was that when C# calls SP, for each parameter that has no value passes 'default' keyword (i found it in SQL Profiler):
... #IsStop=0,#StopEndDate=default,#Satellite=0, ...
in my case my parameter Type was DateTime :
#StopEndDate datetime
. I Solved my problem by seting default value to this parameter in Stored Procedure :
#StopEndDate datetime=null
Try remove #:
cmd.Parameters.Add("username", SqlDbType.NVarChar).Value = "bob101";
Sorry if someone has already given an answer to this, I have been browsing the site and trying tips and bits of code for hours, to no avail.
I have a stored procedure which basically retrieves the id of an element, if this element exists, and zero if it doesn't.
Here we go:
PROCEDURE [dbo].[ChecksProductExistence]
#Product_Name varchar(50),
#Return_Value Int output
AS
BEGIN
IF EXISTS (SELECT prod.ProductID
FROM dbo.Products prod
WHERE prod.ProductName = #Product_Name)
SET #Return_Value = 1;
ELSE
SET #Return_Value = 0;
END
Okay, so far so good. Execute that in my database, and it works like a charm... not that it's such complex code.
Then, in Visual Studio, I coded the following:
private static bool checkExistingProduct(ShoppingListContext ctx, Product product)
{
var cmd = ctx.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[ChecksProductExistence]";
ctx.Database.Connection.Open();
int bla = 0;
SqlParameter inParameter = new SqlParameter();
inParameter.ParameterName = "#Product_Name";
inParameter.SqlDbType = SqlDbType.NVarChar;
inParameter.Direction = ParameterDirection.Input;
inParameter.Value = product.ProductName;
SqlParameter outParameter = new SqlParameter();
outParameter.ParameterName = "#Return_Value";
outParameter.SqlDbType = SqlDbType.Int;
outParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(inParameter);
cmd.Parameters.Add(outParameter);
bla = cmd.ExecuteNonQuery();
Console.WriteLine(outParameter.Value);
Console.ReadLine();
if ((int)outParameter.Value == 1) return true; else return false;
}
As you can see... simple enough. I create a command, add parameters, execute it, try some decision making on the output.
But... I get an error on the
cmd.ExecuteNonQuery();
line. I have changed it to ExecuteScalar, for example, but still no luck. I have executed it without the "bla = ...", and still the same.
The error I get is
An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
Additional information: Procedure or function 'ChecksProductExistence' expects parameter '#Product_Name', which was not supplied.
But then again, not only can you see clearly in the code that I AM IN FACT SUPPLYING IT, but also on the debug session I can explore the cmd object and browse the parameters, and I can see that IT IS THERE, and the values are correct...
So what else can I do?? Am I making some silly mistake I can't see...?
As stated in the documentation for SqlCommand.CommandType you have to set it to CommandType.StoredProcedure and set the CommandText to the name of the stored procedure. It defaults to CommandType.Text where you have to include the named parameters in the text of the query.
When you set the CommandType property to StoredProcedure, you should
set the CommandText property to the name of the stored procedure. The
command executes this stored procedure when you call one of the
Execute methods.
The Microsoft .NET Framework Data Provider for SQL
Server does not support the question mark (?) placeholder for passing
parameters to a SQL Statement or a stored procedure called with a
CommandType of Text. In this case, named parameters must be used. For
example:
SELECT * FROM Customers WHERE CustomerID = #CustomerID
So, just add the following
cmd.CommandType = CommandType.StoredProcedure;
somewhere before executing it.
I am using a bacgroundworker in my C# Winforms app to call a stored procedure in SQL Server. The reason I am doing this is that I am using raiserror messages to send back rows counts and messages to a progress bar that shows the progress of the stored procedure. That all works fine. My problem is at the end of the stored procedure I have a message that returns a success message. The success message is declared an an output parameter in the stored procedure.
DECLARE #returnMessage OUTPUT
Then I say something like:
SET #returnMessage = "Posting dues has successfully completed on ' + GetDate()
Now in my app, I have my DoWork method where I connect and execute my stored procedure. Here is the pertinent code:
conn.InfoMessage += (o, args) => self.ReportProgress(0, args.Message);
SqlCommand cmd = new SqlCommand("ua_sp_PostPeriodicDues", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;
cmd.Parameters.Add(new SqlParameter("#periodCode", periodCode));
cmd.Parameters.Add(new SqlParameter("#nextPostingDate", nextPostingDate));
cmd.Parameters.Add(new SqlParameter("#repost", repost));
cmd.Parameters.Add(new SqlParameter("#localFieldName", localFieldName));
cmd.Parameters.Add(new SqlParameter("#userCd", userCd));
cmd.Parameters.Add(new SqlParameter("#runNow", runNow));
cmd.Parameters.Add(new SqlParameter("#returnMessage", returnMessage)).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
returnMessage = cmd.Parameters["#returnMessage"].Value.ToString();
returnMessage is a string that is defined at the class level so it is available to the RunWorkerCompleted method.
In my RunWorkerCompleted method I have the following lines.
form.Kill(); //closes progress bar modeless dialog
Cursor.Current = Cursors.Default;
MessageBox.Show(returnMessage); //display the success
Problem is the returnMessage variable always returns an empty string. I am just using an output parameter in the stored procedure with no return. Does my output parameter have to be handled differently on the C# side because it is in a backgroundworker? Is there a better way to return back a success at the end of the stored procedure. Is doing with a backgroundworker causing the problem?
I would break it down and add the Output Paramter and declare the datatype as well as follows:
SqlParameter returnMessage = new SqlParameter("#returnMessage", SqlDbType.String);
returnMessage.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnMessage);
cmd.Open();
cmd.ExecuteNonQuery();
var result = returnParameter.Value;
-Please change this code
SET #returnMessage = 'Posting dues has successfully completed on ' + GetDate()
to
SET #returnMessage = 'Posting dues has successfully completed on ' + GetDate()
DECLARE #returnMessage VARCHAR(100) OUTPUT
is not valid TSQL. This should return an error.
OUTPUT parameters have to be actual parameters of the stored procedure. You can't declare them inside the procedure scope and try to return them from there.
Make the output parameter part of the SP definition and it should work.
You say it's working in the SQL Server query analyzer, but not in (I assume) production. The likely culprit is a schema issue. You are referencing your stored procedure without schema-qualifying the name. Reference to SQL objects that are not schame-qualified are looked up in the following manner:
First the current connection's default schema is probed for an object matching the referenced name. If found, the reference is resolved. Otherwise...
The dbo schema is probed for an object matching the referenced name.
It is possible to have multiple objects of the same name that are owned by different schemas, with the result that different logins (attached to different default schemas) can (and will) resolve such unqualified references differently. With the odd results you seem to be seeing.
Unless you have a very good reason not to do so, always schema-qualify your object references and SQL create statements.
That being said, given this stored procedure:
create procedure dbo.mySproc
#p1 varchar(32) ,
#p2 varchar(8000) output
as
set #p2 = case
when #p1 is null then 'Hello, <null>!'
else 'Hello, ' + #p1
end
return 0
go
This code should do you:
using ( SqlConnection connection = new SqlConnection(connectString) )
using( SqlCommand cmd = connection.CreateCommand() )
{
cmd.CommandText = "dbo.mySproc" ;
cmd.CommandType = CommandType.StoredProcedure ;
cmd.Parameters.AddWithValue( "#p1" , "Emily" ) ;
cmd.Parameters.Add( "#p2" , SqlDbType.VarChar , 8000 );
cmd.Parameters["#p2"].Direction = ParameterDirection.Output ;
connection.Open();
int rc = cmd.ExecuteNonQuery();
connection.Close();
string message = (string) cmd.Parameters["#p2"].Value ;
Console.WriteLine( "The message is: {0}",message);
}
And should produce
The message is: Hello, Emily