I have a method that executes a SqlCommand and returns the result to a winforms application.
My method is this:
public bool ApplyRoles(string roleApp, string roleAppPassword)
{
Command = new SqlCommand("EXEC sp_setapprole #roleApp, #rolePassword", Connection);
AssignParam("roleApp", roleApp, SqlDbType.VarChar);
AssignParam("rolePassword", roleAppPassword, SqlDbType.VarChar);
bool ret = Command.ExecuteNonQuery() == -1;
return ret;
}
and the AssignParam method is this:
public void AssignParam(string name, object value, SqlDbType type)
{
var parameter = new SqlParameter(name, type)
{
Value = value ?? DBNull.Value
};
Command.Parameters.Add(parameter);
}
Now, this ApplyRoles method throws the exception: Application roles can only be activated at the ad hoc level. but if i change the ApplyRoles to this:
public bool ApplyRoles(string roleApp, string roleAppPassword)
{
Command = new SqlCommand(string.Format("EXEC sp_setapprole '{0}', '{1}'", roleApp, roleAppPassword), Connection);
bool ret = Command.ExecuteNonQuery() == -1;
return ret;
}
The method works fine.. so i'm guessing that the problem is in the AssignParam method.
What is the problem? I don't want to use the "working" method because i could have sql injection on it.
sp_setapprole uses the parameter names #rolename and #password. You have to use those parameter names if you are passing the parameter names into the a SqlCommand` instance. It was working for you in your second example because you were passing only the parameter values in the correct order that the stored proc was expecting them.
Since you're executing a stored procedure, use CommandType.StoredProcedure
Also put the '#' character in front of your parameter names.
Command = new SqlCommand("sp_setapprole", Connection);
Command.CommandType = CommandType.StoredProcedure;
Command.Parameters.AddWithValue( #rolename, roleApp);
Command.Parameters.AddWithValue( #password, rolePassword);
bool ret = Command.ExecuteNonQuery() == -1;
return ret;
Related
Here am Passing employeename as parameter but declared inside the method instead of at the method call and then added as a parameter to the stored procedure. But the result i get here includes all the employeename data. What am I trying to achieve here is to get data for John from GetEmployee method, instead am getting data for all employeenames in the view. Any ideas where am doing wrong?
public IList<EmployeeModel> GetEmployee()
{
string employeeName= "John";
List<EmployeeModel> empdata;
using (DbCommand cmd = this.UoW.CreateCommand())
{
cmd.CommandText = "getemployee";
cmd.CommandType = CommandType.StoredProcedure;
cmd.AddParameter("employeeName", DbType.String, ParameterDirection.Input, employeeName);
cmd.AddParameter("outputcur", Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor, ParameterDirection.Output, string.Empty);
empdata= cmd.ExecuteQuery<EmployeeModel>();
}
return empdata;
}
}
Here's the code in procedure
PROCEDURE getemployee(employeeName VARCHAR, outputcur OUT SYS_REFCURSOR ) IS
BEGIN
OPEN outputcur FOR SELECT
*
FROM
V_EMPLOYEE
WHERE
empname= employeeName; //John is the employeename
END;
And here in this method which is different from above, am passing parameter while calling it,and it works
public IList<AllEmployeeModel> GetAllEmployees(string employeeId)
{
List<AllEmployeeModel> allempdata= new List<AllEmployeeModel>();
using (DbCommand cmd = this.UoW.CreateCommand())
{
cmd.CommandText = "getallemployees";
cmd.CommandType = CommandType.StoredProcedure;
cmd.AddParameter("employeeId", DbType.String, ParameterDirection.Input,employeeId);
cmd.AddParameter("output",Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor,ParameterDirection.Output, string.Empty);
allempdata= cmd.ExecuteQuery<AllEmployeeModel>();
}
return allempdata;
}
I saw many questions on stack overflow, non of them touched my own problem
procedure or function expects parameter which was not supplied
I created this SQL Server stored procedure:
CREATE proc [dbo].[spAddCustomer]
#cuName varchar(50),
#cuAddress varchar(50),
#cuMobile varchar(50),
#cuImage image,
#cityId int,
#exist int output
AS
BEGIN
IF NOT EXISTS(SELECT Cu_Mobile FROM tblCustomers WHERE Cu_Mobile = #cuMobile)
BEGIN
INSERT INTO tblCustomers (Cu_Name, Cu_Address, Cu_Mobile, Cu_Image, City_ID)
VALUES (#cuName, #cuAddress, #cuMobile, #cuImage, #cityId)
SET #exist = 1
END
ELSE
SET #exist = 0
END
In my Data Access Layer I have this method that is responsible for non-query commands:
public static int ExecuteNonQuery(string query, CommandType type, params SqlParameter[] arr)
{
int outParam;
SqlCommand cmd = new SqlCommand(query, cn);
cmd.Parameters.AddRange(arr);
cmd.CommandType = type;
int i = cmd.ExecuteNonQuery();
foreach (SqlParameter param in arr)
{
if (param.Direction == ParameterDirection.Output)
{
outParam = (int)cmd.Parameters[param.ToString()].Value;
return outParam;
}
}
return i;
}
The method responsible for creating parameters:
public static SqlParameter CreateParameter(string name, SqlDbType type, object value, ParameterDirection pd = ParameterDirection.Input)
{
SqlParameter pr = new SqlParameter();
pr.ParameterName = name;
pr.Direction = pd;
pr.SqlDbType = type;
pr.SqlValue = value;
return pr;
}
And this method in the Business Layer, pass the arguments from the Presentation Layer
public static int spAddCustomer(string cusName, string cusAddress, string cusMobile, byte[] arrImg, int cityId)
{
DataAccessLayer.Open();
int i = DataAccessLayer.ExecuteNonQuery("spAddCustomer", CommandType.StoredProcedure,
DataAccessLayer.CreateParameter("#cuName", SqlDbType.VarChar, cusName),
DataAccessLayer.CreateParameter("#cuAddress", SqlDbType.VarChar, cusAddress),
DataAccessLayer.CreateParameter("#cuMobile", SqlDbType.VarChar, cusMobile),
DataAccessLayer.CreateParameter("#cuImage", SqlDbType.Image, arrImg),
DataAccessLayer.CreateParameter("#cityId", SqlDbType.Int, cityId),
DataAccessLayer.CreateParameter("#exist", SqlDbType.Int, null, ParameterDirection.Output));
DataAccessLayer.Close();
return i;
}
When the user Click add a new record is inserted into the table (tblCustomers)
private void btnAU_Click(object sender, EventArgs e)
{
byte[] imgArr;
if (PbCustomer.Image == null)
imgArr = null;
else
{
MemoryStream ms = new MemoryStream();
PbCustomer.Image.Save(ms, PbCustomer.Image.RawFormat);
imgArr = ms.ToArray();
}
int cityId = int.Parse(cmbCities.SelectedValue.ToString());
try
{
int exist = CustomerClass.spAddCustomer(txtName.Text, txtAddress.Text, txtMobile.Text, imgArr, cityId);
if (exist == 1)
{
MessageBox.Show("A new customer has been saved");
txtAddress.Text = txtMobile.Text = txtName.Text = "";
PbCustomer.Image = null;
}
else
MessageBox.Show("A customer with the same mobile number\nalready exists, add new number!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
But when I click the Add button (passing null image), I get this error:
procedure or function 'spAddCustomer' expects parameter '#cuImage'
which was not supplied
Despite the table tblCustomers accept null values
I just found that I can set default values for the parameter in the stored procedure:
ALTER proc [dbo].[spAddCustomer]
#cuName varchar(50)=null,
#cuAddress varchar(50)=null,
#cuMobile varchar(50)= null,
#cuImage image= null,
#cityId int= null,
#exist int output
And this solved my problem!
This is helpful specifically with null images from the PictureBox, since I have a helper method that checks for empty strings.
You need to check your input for null and use DBNull.Value when you creating the parameters. If you pass just null as a parameter - ADO.Net will ignore that.
EDIT:
You can add that check into your custom method DataAccessLayer.CreateParameter()
I have created a linq2sql project in which I have an extension method for calling SPs.
This extension method has few features-
It can call SP with Table Valued Parameters.
It can accepts both input and output parameters
It will handle multiple result set
Extension Method -
public partial class TestLinq2SqlDataContext : DataContext
{
public IMultipleResults ExceuteProcedure(string spName, IEnumerable<SqlParameter> parameters, SqlConnection sqlConnection, out SqlDataReader reader)
{
reader = null;
try
{
sqlConnection.Open();
var cmd = new SqlCommand
{
Connection = sqlConnection,
CommandText = spName,
CommandType = CommandType.StoredProcedure
};
cmd.Parameters.AddRange(parameters.ToArray());
reader = cmd.ExecuteReader();
return Translate(reader);
}
catch (Exception)
{
}
return null;
}
}
I am calling below SP -
CREATE PROCEDURE USP_OutPutParameterCheck(
#Id int OUTPUT,
#Name nvarchar(50) OUTPUT)
AS
BEGIN
SET #Id = 12 SET #Name = N'NameSet for OutputParameter'
END
My C# code is
public static void Main(){
context = new TestLinq2SqlDataContext();
#region USP_OutPutParameterCheck
var connection1 = context.Connection as SqlConnection;
SqlDataReader dataReader1;
var outParam1 = new SqlParameter
{
Direction = ParameterDirection.Output,
Value = "Abc",
DbType = DbType.String,
ParameterName = "#Name"
};
var outParam2 = new SqlParameter
{
Direction = ParameterDirection.Output,
Value = 1,
DbType = DbType.Int32,
ParameterName = "#Id"
};
var parameters11 = new[]
{
outParam1,
outParam2
};
var data21 = context.ExceuteProcedure("USP_OutPutParameterCheck", parameters11, connection1, out dataReader1);
}
Now When I check the values of output parameters in debug mode I am getting the #Id's value perfect
but for #Name parameter I'm only getting 'N' value instead of 'NameSet for OutputParameter'
Can anyone help me out where I am going wrong in this?
Thanks
UPDATE :
Adding Screenshot when seeing the values of parameters in debug mode -
I think You must specifcy the Size of the outParam1.
See: https://msdn.microsoft.com/en-us/library/system.data.common.dbparameter.size(v=vs.110).aspx
For bidirectional and output parameters, and return values, you must
set the value of Size. This is not required for input parameters, and
if not explicitly set, the value is inferred from the actual size of
the specified parameter when a parameterized statement is executed.
I have an issue. please help to solve my problem
I have a SQL function
function [dbo].[fnKudishikaAmt]
(#ParishName nvarchar(100), #Hno int, #dateto datetime = Null)
Returns Decimal(15,2)
This function shows proper result by using the execute command
Select dbo.fnKudishikaAmt('St.George Malankara Catholic Church', 29, default)
My requirement is this function should be called from C#
I am getting the error
Conversion failed when converting datetime from character string
Code:
public double kudishikatotal(string ParishName, Int32 HouseNo)
{
String SQLText = "select ChurchDB.dbo.fnKudishikaAmt(#ParishName, #Hno, #dateto) as fnresult";
SqlCommand cmd = new SqlCommand(SQLText);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#ParishName", ParishName);
cmd.Parameters.AddWithValue("#Hno", HouseNo);
cmd.Parameters.AddWithValue("#dateto", "default");
string rval = GetSingleValue(cmd);
double kudiamt = 0;
if (rval != null)
{
kudiamt = Convert.ToDouble(rval);
}
return kudiamt;
}
private static string GetSingleValue(SqlCommand cmd)
{
string ConString = connectionstring();
string returnvalue = "";
using (SqlConnection con = new SqlConnection(ConString))
{
cmd.Connection = con;
con.Open();
returnvalue = cmd.ExecuteScalar().ToString();
con.Close();
}
return returnvalue;
}
If you've declared default value for parameter in stored procedure - then you can just not pass this parameter from c# code at all, and in this case it will have default value.
In your case exception thrown because it's impossible to convert string "default" to SqlDateTime which is your parameter type.
YOu can use if condition while sending the datetime parameter.
if(some condition)
{
cmd.Parameters.AddWithValue("#dateto", dateTimeValue);
}
Here datetimeValue is the value you want to pass. So you will be passing dateTimeValue only if required.
The error is due to the string "default" you passed.
I am trying to check if a user is in my database, my return value from my function is either a 't' or an 'f'. as below:
CREATE OR REPLACE FUNCTION LOGIN
(p_Naam in varchar2
,p_Wachtwoord in varchar2)
return varchar2
is
v_count number;
BEGIN
select count(*) into v_count
from Lid
where Naam = p_Naam
and Wachtwoord = p_Wachtwoord;
if v_count > 0 then
return 't';
end if;
return 'f';
END LOGIN;
now i call this function with my C# code as below:
public bool LogIn(string gebruikersnaam, string wachtwoord)
{
string s;
var cmd = new OracleCommand
{
Connection = conn,
CommandText = "Login",
CommandType = CommandType.StoredProcedure
};
cmd.Parameters.Add("p_Naam", OracleDbType.Varchar2).Value = gebruikersnaam;
cmd.Parameters.Add("p_Wachtwoord", OracleDbType.Varchar2).Value = wachtwoord;
cmd.Parameters.Add("return_value", OracleDbType.Varchar2, ParameterDirection.ReturnValue);
try
{
conn.Open();
cmd.ExecuteNonQuery();
s = cmd.Parameters["return_value"].Value.ToString();
}
finally
{
conn.Close();
}
return s == "t";
}
when i try this funcion within my oracle developer i get an output.
only in my C# code, s always comes out as ""
in my sql developer the following gives me 't'
BEGIN
dbms_output.put_line(LOGIN('Willem Koonings', 'willem'));
END;
I haven't been working with OracleCommands for a while, but i would suggest this change:
CommandText = "Login(:p_Naam, :p_Wachtwoord)";
The long solution which I bets works (change type to text though):
CommandText = "select Login(:p_Naam, :p_Wachtwoord) return_value from dual";
When you have this in your code:
s = cmd.Parameters["return_value"].Value.ToString();
It implies, to me, that your command had somethink akin to this:
insert into test (user_name, create_date)
values (:USERNAME, sysdate)
returning user_id into :return_value
I've never seen a stored procedure use a "returning" as such. That doesn't automatically mean it can't be done, but it doesn't seem consistent with how I've used it and seen it used.
Since you are running a stored proc that returns a scalar value, this would probably suit you better:
string result = (string)cmd.ExecuteScalar();
You need to place the "return value" parameter first in the index, as far as i can tell from working with Oracle it doesn't pass the names of the parameters to the Oracle call, it is absolute placing.
Hope this solves your problems :)
Dom
ParameterDirection.ReturnValue could return only a numeric value, not a string or single char.
(At least in Sql Server). Try to change your function to return an integer and your parameters collection to receive an integer. (I don't have Oracle to test, please correct me if there are some syntax errors)
See this reference (for Sql Server)
CREATE OR REPLACE FUNCTION LOGIN
(p_Naam in varchar2
,p_Wachtwoord in varchar2)
return INTEGER
is
v_count number;
BEGIN
select count(*) into v_count
from Lid
where Naam = p_Naam
and Wachtwoord = p_Wachtwoord;
if v_count > 0 then
return 1;
end if;
return 0;
END LOGIN;
....
cmd.Parameters.Add("p_Naam", OracleDbType.Varchar2).Value = gebruikersnaam;
cmd.Parameters.Add("p_Wachtwoord", OracleDbType.Varchar2).Value = wachtwoord;
cmd.Parameters.Add("return_value", OracleDbType.Int32, ParameterDirection.ReturnValue);
....
int result = Convert.ToInt32(cmd.Parameters["return_value"].Value);
if(result == 0)
// fail
else
// success...
Instead of 'Return' statement why don't you declare a out parameter .Let me know if iam not clear
Just found out this and tested with VS2017 Community edition + 11g.
OracleCommand chkCmd = null;
try
{
chkCmd = new OracleCommand();
chkCmd.CommandText = "login";
chkCmd.CommandType = CommandType.StoredProcedure;
chkCmd.Connection = conn;
OracleParameter mobParam1 = new OracleParameter("p_Naam", OracleDbType.Varchar2, 2000);
mobParam1.Direction = ParameterDirection.Input;
mobParam1.Value = gebruikersnaam;
OracleParameter mobParam2 = new OracleParameter("p_Wachtwoord", OracleDbType.Varchar2, 2000);
mobParam2.Direction = ParameterDirection.Input;
mobParam2.Value = wachtwoord;
OracleParameter retValue = new OracleParameter("returnVal", OracleDbType.Varchar2, 2000);
retValue.Direction = ParameterDirection.ReturnValue;
chkCmd.Parameters.Clear();
chkCmd.Parameters.Add(retValue);
chkCmd.Parameters.Add(mobParam1);
chkCmd.Parameters.Add(mobParam2);
con.Open();
chkCmd.ExecuteScalar();
string retmsg = Convert.ToString(retValue.Value);
return retmsg=="t";
}
finally
{
con.Close();
chkCmd.Dispose();
con.Dispose();
}
Make Return_Value your first parameter:
cmd.Parameters.Add("Return_Value", OracleDbType.Boolean, ParameterDirection.ReturnValue);