How to check an output DbParameter for null value? - c#

I'm using System.Data.Common.DbCommand.ExecuteNonQueryAsync to call an Oracle stored procedure that has one output parameter o_err_msg which (you guessed it) is a VARCHAR2 error message when an exception occurs or null when the procedure succeeds. So, after calling `ExecuteNonQueryAsync, I'm trying to check if that parameter is null, to see if there was an error or not. But can't find a way to actually do it.
I've tried comparing (through both the == operator and the Equals method) the Value property of the parameter to null, to DBNull.Value and calling System.Convert.IsDBNull on it. All of these return null. I've even tried converting it to string (either through the ToString method or System.Convert.ToString) and then calling string.IsNullOrEmpty, but the resulting string is "null".
The code I'm running is somewhat similar to this:
DbCommand cmd = dbConnection.CreateCommand();
cmd.CommandText = "PCKG_FOO.PROC_BAR";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("o_err_msg", OracleDbType.Varchar2, 4000, "", ParameterDirection.Output));
await cmd.ExecuteNonQueryAsync();
if (cmd.Parameters["o_err_msg"].Value != null)
throw new InvalidOperationException(cmd.Parameters["o_err_msg"].Value.ToString());
Even though, in this example, I'm initializing the parameters as OracleParameter, in my code I only have DbParameter accessible and I'd prefer if I didn't have to cast it to OracleParameter or anything Oracle-specific.
Is there any way I can do this?
Thanks in advance.

I encountered the same problem today, the fowling code should be a workarround.
OracleParameter out1 = new OracleParameter("out1", OracleDbType.Varchar2, ParameterDirection.Output);
out1.Size = 1000;
Oracle.ManagedDataAccess.Types.OracleString out1Value = (Oracle.ManagedDataAccess.Types.OracleString)out1.Value;
if (!out1Value.IsNull)
{
// do something
}

Related

Need example of calling stored procedure sp_SSISCloneConfiguration from a c# program on SQL Server

When I use this code below, I get a -1 returned from line
cmd.ExecuteNonQuery()
It may have something to do with InvalidCastException.
When we run this stored procedure manually in SSMS, it produces a SQL script in its output which we then copy and paste in a new window and run that to get what we want.
Any ideas of why it's not working from C#?
I knew the connection to the server is good.
using (SqlCommand cmd = new SqlCommand("dbo.sp_SSISCloneConfiguration", sqlConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#project", SqlDbType.VarChar).Value = projectName;
cmd.Parameters.Add("#destinationProject", SqlDbType.VarChar).Value = projectName;
cmd.ExecuteNonQuery();
}
Because ExecuteNonQuery() returns "The number of rows affected."
If you're expecting data as a result, you probably meant to use ExecuteReader() which returns "A SqlDataReader object", or perhaps ExecuteScalar() which returns "The first column of the first row in the result set, or a null reference if the result set is empty."
For example:
var result = cmd.ExecuteScalar();
Note that the type of result is object. So if "it produces a sql script in its output" then you would probably need to convert it to a string, for example:
var result = cmd.ExecuteScalar()?.ToString();
Note the ? operator being used, because ExecuteScalar() could return null.

Call an Oracle Function from C# with Nulls

I'm trying to call an Oracle Function from our C# application, but I either get the following errors. I think I have two problems:
I want to call this function, but some of the parameters can be null on the C# side so I don't know how to handle them.
I don't know if I need to add the return value to the parameters with ParameterDirection.ReturnValue on the OracleParameter object.
This is what I'm trying:
public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
OracleCommand cmd = null;
try
{
StringBuilder sql = new StringBuilder();
sql.Append(" pack_SomePack.func_SearchRowCount");
cmd = new OracleCommand(sql.ToString(), this.Connection);
cmd.CommandType = CommandType.StoredProcedure;
// Don't know if I should add this guy
// cmd.Parameters.Add(new OracleParameter("RowCount", OracleDbType.Int16, ParameterDirection.ReturnValue));
cmd.Parameters.Add(new OracleParameter("FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("grpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("catCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("typCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("memNbr", OracleDbType.Long, memNbr, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("SubNbr", OracleDbType.Long, SubNbr, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("searchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("statCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("showUncategorized", OracleDbType.Char, showUncategorized? "Y" : "N", ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("debugYN", OracleDbType.Varchar2, debugYN, ParameterDirection.Input));
cmd.BindByName = true;
int activityRowCount = Convert.ToInt16(cmd.ExecuteScalar()); // Error here
return activityRowCount;
}
My function does the following:
FUNCTION func_SearchRowCount
(
in_FromDate IN DATE,
in_ThruDate IN DATE,
in_GrpCds IN VARCHAR2,
in_CatCds IN VARCHAR2,
in_TypCds IN VARCHAR2,
in_MemNbr IN Actv.PersNbr%TYPE,
in_SubNbr IN Actv.SubNbr%TYPE,
in_SearchBy IN VARCHAR2,
in_dispActivity IN VARCHAR2,
in_StatCds IN Ams.StatCd%TYPE,
in_UncategorizedYN IN CHAR,
in_DebugYN IN CHAR
) RETURN NUMBER AS
lvnCount NUMBER;
lvsSqlStr VARCHAR2(2000);
BEGIN
lvsSqlStr := 'SELECT COUNT(*) FROM SomeTable WHERE (Include a bunch of clauses..)';
BEGIN
EXECUTE IMMEDIATE lvsSqlStr
INTO lvnCount
USING (All the parameters);
END;
RETURN lvnCount;
END func_SearchRowCount;
I get the following error when running what's above.
PLS-00306: wrong number or types of arguments in call to 'FUNC_SEARCHROWCOUNT'
All the variables are bound with the correct amount, although I read somewhere that ODP.NET will remove the parameters with null as there .Value. Is this true? What should I pass in to indicate that there is no value for that parameter then?
You need 4 things at a minimum:
The first two: call ExecuteNonQuery and not ExecuteScalar as discussed in this MSDN thread and create the return value parameter. About a third of the way down on Accessing Oracle 9i Stored Procedures it shows this code and says
You execute the function in the same way as a stored procedure. Use a ParameterDirection.ReturnValue parameter to get the result returned by the function.
On the third, do use DbNull.Value because it is specifically designed as a placeholder to represent null values in a database, whereas null has meaning only for .NET. (Well, null is probably ok because the Oracle driver is probably smart enough to handle it; DbNull.Value is a good habit though because you're being explicit). You can do something like
new OracleParameter("typCds", OracleDbType.Varchar2, typCds ?? (object)DbNull.Value, ParameterDirection.Input));
And finally, you have bind by name on your parameters, but the names don't match the names of your parameters. Match the names exactly or bind by position.
As to the specific error, the return value is "an argument" and didn't bind he parameters correctly. Oracle wanted 13 parameters and you effectively gave it none.
there seems to be several problems with your code.
Oracle Type LONG is not same like in C#, LONG in Oracle DB allows you to store character data up to 2GB size. In C# it's an numeric type using 64 Bit. Since your submitted code does not explain what type of data your parameters in_MemNbr, in_SubNbr and in_StatCds in the package function are, i can only guess, what it is depending on your definitions of the parameter list in your c# method.
Your parameter names in C# in the "new OracleParameter("")" statements does not match the function parameters exactly. In Pl/Sql you added an "in_" prefix, but removed it in the c# code. With "cmd.BindByName = true;" you say to ODP.Net "Hey, bind the parameters in the collection by name rather than using position". In this case they must match exactly.
Your C# return value of the method is int (System.Int32), the return value of the PlSql package function is NUMBER. ODP.Net seems to return decimal in C# in case of numbers without specified scale. Maybe you run into a conversion/invalidcast exception when ODP.Net tries to convert the oracle number type into short (Int16) internally. Maybe you get an out of range exception when the returned count is greater than short.MaxValue. Try to specify Int32 as return value in your return value parameter creation.
OracleCommand implements IDisposable interface. Please ensure that your command is disposed, when not needed anymore, since the implementation of IDisposable interfaces in objects shows you that the object creates/uses some resources (managed or unmanaged) and must release them, when operations finished. Shortest way is to use the
"using" keyword of C#, which ensures a call of cmd.Dispose() when code execution leaves the block regardless if exception occured or block ends with success.
public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
using (var cmd = new OracleCommand("pack_SomePack.func_SearchRowCount", this.Connection))
using (var result = new OracleParameter("result", OracleDbType.Int32, ParameterDirection.ReturnValue))
using (var fromDateParam = new OracleParameter("in_FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input))
using (var thruDateParam = new OracleParameter("in_ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input))
using (var grpCdsParam = new OracleParameter("in_GrpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input))
using (var catCdsParam = new OracleParameter("in_CatCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input))
using (var typCdsParam = new OracleParameter("in_TypCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input))
using (var memNbrParam = new OracleParameter("in_MemNbr", OracleDbType.Int64, memNbr, ParameterDirection.Input))
using (var subNbrParam = new OracleParameter("in_SubNbr", OracleDbType.Int64, SubNbr, ParameterDirection.Input))
using (var searchByParam = new OracleParameter("in_SearchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input))
using (var dispActivityParam = new OracleParameter("in_dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input))
using (var statCdsParam = new OracleParameter("in_StatCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input))
using (var uncategorizedYnParam = new OracleParameter("in_UncategorizedYN", OracleDbType.Char, showUncategorized ? "Y" : "N", ParameterDirection.Input))
using (var debugYnParam = new OracleParameter("in_DebugYN", OracleDbType.Char, debugYN, ParameterDirection.Input))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(result);
cmd.Parameters.Add(fromDateParam);
cmd.Parameters.Add(thruDateParam);
cmd.Parameters.Add(grpCdsParam);
cmd.Parameters.Add(catCdsParam);
cmd.Parameters.Add(typCdsParam);
cmd.Parameters.Add(memNbrParam);
cmd.Parameters.Add(subNbrParam);
cmd.Parameters.Add(searchByParam);
cmd.Parameters.Add(dispActivityParam);
cmd.Parameters.Add(statCdsParam);
cmd.Parameters.Add(uncategorizedYnParam);
cmd.Parameters.Add(debugYnParam);
cmd.BindByName = true;
cmd.ExecuteNonQuery();
return Convert.ToInt32(result.Value);
}
}

Stored procedure expects a parameter I am already passing in

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;

What is the wrong with Scope_Identity?

I tried milions of methods to make scope identity work. It is just returns __Page !!
Query = "INSERT INTO seekers(name,sname,lname,status,gender,dob,major,experince,email,password,phone,valid,city) values(#name,#sname,#lname,#status,#gender,#dob,#major,#exp,#email,#password,#phone,0,#city);SELECT SCOPE_IDENTITY();";
// setting up command definition
Command = new SqlCommand(Query, Connection);
// setting up command parameters
Command.Parameters.AddWithValue("email", txt_email.Text);
Command.Parameters.AddWithValue("gender", lst_gender.SelectedValue);
Command.Parameters.AddWithValue("status", lst_status.SelectedValue);
Command.Parameters.AddWithValue("phone", long.Parse("968" + txt_phone.Text));
Command.Parameters.AddWithValue("password", txt_password.Text);
Command.Parameters.AddWithValue("exp", lst_exp.SelectedValue);
Command.Parameters.AddWithValue("city", lst_exp.SelectedValue);
Command.Parameters.AddWithValue("major", lst_major.SelectedValue);
Command.Parameters.AddWithValue("name", txt_name.Text);
Command.Parameters.AddWithValue("sname", txt_sname.Text);
Command.Parameters.AddWithValue("lname", txt_lname.Text);
Command.Parameters.AddWithValue("dob", cld_birth.SelectedDate);
int ID = (int)Command.ExecuteScalar();
Try Out Parameter as follow...
Query = "INSERT INTO seekers(name,sname,lname,status,gender,dob,major,experince,email,password,phone,valid,city) values(#name,#sname,#lname,#status,#gender,#dob,#major,#exp,#email,#password,#phone,0,#city);SET #ID=SCOPE_IDENTITY();"
//Your Parameters..
SqlParameter ID=new SqlParameter();
ID.Name="#ID";
ID.Direction=ParameterDirection.Output;
Command.Parameters.Add(ID);
Command.ExecuteNonQuery();
int id=(int)ID.Value;
or
Tryb to Cast Output as follow...
Query = "INSERT INTO seekers(name,sname,lname,status,gender,dob,major,experince,email,password,phone,valid,city) values(#name,#sname,#lname,#status,#gender,#dob,#major,#exp,#email,#password,#phone,0,#city);SELECT CAST(scope_identity() AS int);"
int id= (Int32)Command.ExecuteScalar();
use set nocount off and try
As First execute statement is insert the returned value is number of records effected
SCOPE_IDENTITY will return a decimal, try:
int ID = (int) (decimal) Command.ExecuteScalar();
It's not very clear what you mean by:
It is just returns __Page !!
Presumably the posted code is throwing an exception, and that's resulting in some higher level code doing whatever it is you mean by "... returns __Page".
If you look at the exception details, you'll find more about what happened: which I suspect is an InvalidCastException because you're trying to cast the object returned by Command.ExecuteScalar (a boxed decimal) to an int.

Converting from DbCommand object to OracleCommand object

I have inherited a function in an ASP.NET (C#) application where the author used the Microsoft.Practices.EnterpriseLibrary.Data library, but I have been asked to change it so that it uses System.Data.OracleClient. This function uses a stored procedure form a database. itemName, and openDate are string parameters that the function takes in. PKG_AUCTION_ITEMS.IsAuctionItem is the stored procedure function name.
Here is the code that I received:
string result = String.Empty;
Database db = DatabaseFactory.CreateDatabase("OraData");
using (DbCommand cmdDB = db.GetStoredProcCommand("PKG_AUCTION_ITEMS.IsAuctionItem"))
{
db.AddInParameter(cmdDB, "vItemName", DbType.String, itemName);
db.AddInParameter(cmdDB, "vOpenDate", DbType.String, openDate);
db.AddParameter(cmdDB, "ret", DbType.String, 2, ParameterDirection.ReturnValue, false, 0, 0, null, DataRowVersion.Current, null);
db.ExecuteNonQuery(cmdDB);
result = cmdDB.Parameters["ret"].Value.ToString();
}
Here is my code:(connstr is the connection string)
string result = String.Empty;
OracleConnection conn = new OracleConnection(connstr);
OracleCommand cmd = new OracleCommand("PKG_AUCTION_ITEMS.IsAuctionItem",conn);
myCmd.CommandType = CommandType.StoredProcedure;
using (myCmd)
{
myCmd.Parameters.AddWithValue("vItemName", itemName);
myCmd.Parameters.AddWithValue("vOpenDate", openDate);
myCmd.Parameters.AddWithValue("ret", ???);
myCmd.ExecuteNonQuery();
result = myCmd.Parameters["ret"].Value.ToString();
}
I do not understand what the difference between AddInParameter and AddParameter is, and what this line does:
db.AddParameter(cmdDB, "ret", DbType.String, 2, ParameterDirection.ReturnValue, false, 0, 0, null, DataRowVersion.Current, null);
Am I on the right track? Can anyone please help?
Thanks
db.AddParameter adds an output parameter in this case. You need to let the db client library know that you're looking to get the return value back from the sproc call. Hence the call to AddParameter. db.AddInParameter adds a parameter which is only an in-parameter. In the It's a shortcut for db.AddParameter using ParameterDirection.Input. See http://blogs.x2line.com/al/archive/2006/03/25/1579.aspx for a discussion of AddInParameter vs. AddParameter.
Similarly, using OracleClient, AddWithValue is like AddInParameter-- a shortcut to use for input params when you already know the value. Since the return value is, by definition, an output parameter, you can't use AddWithValue. You need to use Parameters.Add() instead.
Now, back to your main question: what's the equivalent code using OracleClient. It's something like this:
string result = String.Empty;
OracleConnection conn = new OracleConnection(connstr);
OracleCommand cmd = new OracleCommand("PKG_AUCTION_ITEMS.IsAuctionItem",conn);
myCmd.CommandType = CommandType.StoredProcedure;
using (myCmd)
{
myCmd.Parameters.AddWithValue("vItemName", itemName);
myCmd.Parameters.AddWithValue("vOpenDate", openDate);
// depending on whether you're using Microsoft's or Oracle's ODP, you
// may need to use OracleType.Varchar instead of OracleDbType.Varchar2.
// See http://forums.asp.net/t/1002097.aspx for more details.
OracleParameter retval = new OracleParameter("ret",OracleDbType.Varchar2,2);
retval.Direction = ParameterDirection.ReturnValue;
myCmd.Parameters.Add(retval);
myCmd.ExecuteNonQuery();
result = myCmd.Parameters["ret"].Value.ToString();
}
We actually do the configuration of the parameters more explicitly, something like this
System.Data.OracleClient.OracleCommand command = new System.Data.OracleClient.OracleCommand("PACKAGE_NAME.STORED_NAME");
command.CommandType = System.Data.CommandType.StoredProcedure;
System.Data.OracleClient.OracleParameter param;
param = new System.Data.OracleClient.OracleParameter("PARAM_NAME_ID", System.Data.OracleClient.OracleType.Number);
param.Value = id;
command.Parameters.Add(param);
param = new System.Data.OracleClient.OracleParameter("PARAM_NAME_RETURN_COUNT", System.Data.OracleClient.OracleType.Number);
param.Direction = System.Data.ParameterDirection.Output;
command.Parameters.Add(param);
...
You see, there is a property direction which we explicitly assign for the parameter that is being returned. The first gets the value of a variable "id" and is a parameter that gets passed TO the stored procedure.
The 2nd one is being returned by the stored procedure, therefore no value is assigned to that parameter value and the direction is set to "System.Data.ParameterDirection.Output"

Categories

Resources