I have a .NET 6 C# app that calls three stored procedures on a SQL Server. Two of these calls work ok, but the third gives a null ref exception at the line:
result = (bool)cmd.ExecuteScalar();
using (var con1 = this.GetSqlConnection())
{
bool result = false;
try
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = OnlinePaymentCheckNurseryChildSProc;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con1;
cmd.Parameters.AddRange(param);
LogSqlParams(cmd.Parameters);
con1.Open();
result = (bool)cmd.ExecuteScalar();
LogInfo(methodName, $"result=:{result}");
LogInfo(methodName, $"Leaving:{methodName}");
return result;
}
catch (Exception ex)
{
LogError(ex, methodName, "Trouble checking nursery child");
return false;
}
}
The stored proc ends with:
IF (#d = #DOB)
BEGIN
SET #Return = 1
END
ELSE
BEGIN
SET #Return = 0
END
RETURN #Return
END
I've called the same stored procedure with the same parameters from SQL Server Management Studio and it works ok.
The key to solving this problem was to use the ExecuteNonQuery method and pass a special param with a "Direction" property of ParameterDirection.ReturnValue.
The working code block can be see below:
using (var con1 = this.GetSqlConnection())
{
try
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = OnlinePaymentCheckNurseryChildSProc;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con1;
cmd.Parameters.AddRange(param);
LogSqlParams(cmd.Parameters);
SqlParameter returnValue = new SqlParameter();
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
con1.Open();
await cmd.ExecuteNonQueryAsync();
int result = (int)returnValue.Value;
LogInfo(methodName, $"result=:{result}");
LogInfo(methodName, $"Leaving:{methodName}");
return result == 1 ? true : false;
}
catch (Exception ex)
{
LogError(ex, methodName, "Trouble checking nursery child");
return false;
}
}
Related
I want to update details. I have code in a data access class. But after executing ExecuteScalar(), it goes to the catch block and shows an exception as null.
Program :
public bool UpdateData(Customer objcust) // passing model class object because it contains all customer properties.
{
SqlConnection con = null;
// string result = "";
//int rows = 0;
try
{
string connectionString = #"server=(local)\SQLExpress;database=CustDemo;integrated Security=SSPI;";
con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("UPDATE Customer SET Name = #Name , Address = #Address, Gender =#Gender , City=#City WHERE Customer.CustomerID = #CustomerID",con);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#Name", objcust.Name);
cmd.Parameters.AddWithValue("#Gender", objcust.Gender);
cmd.Parameters.AddWithValue("#Address", objcust.Address);
cmd.Parameters.AddWithValue("#City", objcust.City);
con.Open();
cmd.ExecuteScalar();
return true;
}
catch(Exception ex)
{
return false;
}
}
Instead of cmd.ExecuteScalar(); Try to use
cmd.ExecuteNonQuery ();
ExecuteNonQuery is used specifically executing UPDATE, INSERT, or DELETE statements.
I'm trying to execute a stored procedure and print the output, but when I run the below code I'm getting error like "Procedure or function 'SPInsertLocal' expects parameter '#RES', which was not supplied."
private void InsertPdtLocal(string code, string PON,string Qty)
{
string str = Properties.Settings.Default.conLocal;
SqlConnection con = new SqlConnection(str);
SqlCommand cmd = new SqlCommand("Execute SPInsertLocal #PON,#TCode,#Qty,#Type", con);
try
{
con.Open();
cmd.CommandTimeout = 150;
cmd.Parameters.AddWithValue("#PON", PON);
cmd.Parameters.AddWithValue("#Qty", Qty);
cmd.Parameters.AddWithValue("#TCode", code);
cmd.Parameters.AddWithValue("#Type", Globals.s_type);
SqlParameter output = new SqlParameter("#RES", SqlDbType.Int);
output.Direction = ParameterDirection.Output;
cmd.Parameters.Add(output);
cmd.ExecuteNonQuery();
con.Close();
int id = Convert.ToInt32(output.Value);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
What I'm doing wrong here?
SqlCommand cmd = new SqlCommand("Execute SPInsertLocal #PON,#TCode,#Qty,#Type,#RES", con);
I was not passing the parameter , fixed the issue
You can refactor the code as follows where the using statement is used for the auto management of connection closing and avoid hardcoding Execute statement in c# code which is a bad practice
private void InsertPdtLocal(string code, string PON,string Qty)
{
string str = Properties.Settings.Default.conLocal;
try
{
using (SqlConnection con = new SqlConnection(str))
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.Parameters.AddWithValue("#PON", PON);
cmd.Parameters.AddWithValue("#Qty", Qty);
cmd.Parameters.AddWithValue("#TCode", code);
cmd.Parameters.AddWithValue("#Type", Globals.s_type);
var output = cmd.Parameters.Add("#RES" , SqlDbType.Int);
output.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
int id = Convert.ToInt32(output.Value);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I have textbox and on the leave event I am using oracle function to retrieve data for other textboxs so I made below code but i am getting no data found
private void TB_PRODUCT_DESC_Leave(object sender, EventArgs e)
{
string connstr = "Data Source=JDT; User Id=admin; password=admin;";
string cmdtxt = #"F_GET_PRODUCT_INFO"; //~ Returning CUSTOMER_ID from trigger in database ~//
using (OracleConnection conn = new OracleConnection(connstr))
using (OracleCommand cmd = new OracleCommand(cmdtxt, conn))
{
try
{
cmd.CommandText = cmdtxt;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("TB_PRODUCT_DESC", TB_PRODUCT_DESC.Text));
cmd.Parameters.Add(":V_PRODUCT_DESC", OracleDbType.Varchar2, ParameterDirection.ReturnValue);
conn.Open();
cmd.ExecuteReader();
TB_NOTES.Text = (cmd.Parameters[":V_PRODUCT_DESC"].Value).ToString();
MessageBox.Show(TB_NOTES.Text);
}
catch (Exception EX)
{ MessageBox.Show(EX.Message, "error msg", MessageBoxButtons.OK, MessageBoxIcon.Error); }
}
function I am using below that return one varchar2 value
CREATE OR REPLACE FUNCTION F_GET_PRODUCT_INFO (P_PRODUCT_ID NUMBER)
RETURN VARCHAR2
IS
V_PRODUCT_DESC VARCHAR2 (200);
V_UNIT_PRICE NUMBER;
V_MEASUREMENT_UNIT VARCHAR2(32);
BEGIN
SELECT PRODUCT_DESC,
UNIT_PRICE,
MEASUREMENT_UNIT
INTO V_PRODUCT_DESC,
V_UNIT_PRICE,
V_MEASUREMENT_UNIT
FROM WAREHOUSE
WHERE PRODUCT_ID = P_PRODUCT_ID;
RETURN V_PRODUCT_DESC;
END F_GET_PRODUCT_INFO;
You need to specify a size for the varchar2:
OracelParameter prm = new OracleParameter(":V_PRODUCT_DESC");
prm.Direction = ParameterDirection.ReturnValue;
prm.DbType = OracleDbType.Varchar2;
prm.Size = 200;
cmd.Parameters.Add(prm);
I have a form and I want to retrieve data from a sql table and show it in the form's fields depending on the ?id I enter in the url, but I always get this error:
Procedure or function 'GetAppForm' expects parameter '#id', which was
not supplied.
Note: GetAppForm is the stored procedure.
Here's my code, please help me:
try
{
if (String.IsNullOrEmpty(Request.QueryString["id"]))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand("GetAppForm", sqlConn))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter id = cmd.Parameters.Add("#id", SqlDbType.Int);
id.Direction = ParameterDirection.Input;
id.Value = Request.QueryString["id"];
SqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dataReader.Read())
{
OwnerField.Text = dataReader["Owner"].ToString();
OdBookNoField.Text = dataReader["OD"].ToString();
PdLocField.Text = dataReader["pd"].ToString();
StatementNoField.Text = dataReader["Statmnt"].ToString();
ApplicationNoField.Text = dataReader["AppNo"].ToString();
AppDateField.Text = dataReader["AppDate"].ToString();
areaField.Text = dataReader["Area"].ToString();
areaNoField.Text = dataReader["AreaNo"].ToString();
blockNoField.Text = dataReader["BlockNo"].ToString();
streetNoField.Text = dataReader["StreetNo"].ToString();
}
}
}
}
catch (Exception ex)
{
HttpContext.Current.Response.Write("No Connection!!");
}
finally
{
sqlConn.Close();
}
Change
if (String.IsNullOrEmpty(Request.QueryString["id"]))
to
if (!String.IsNullOrEmpty(Request.QueryString["id"]))
I think you just forgot to negate the String.IsNullOrEmpty condition:
try
{
if (!String.IsNullOrEmpty(Request.QueryString["id"]))
{
Please note, your code is prone to injection.
try
{
if (!String.IsNullOrEmpty(Request.QueryString["id"]))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand("GetAppForm", sqlConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#id", Request.QueryString["id"]);
SqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
//SqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.SingleRow);
while (dataReader.Read())
{
OwnerField.Text = dataReader["Owner"].ToString();
OdBookNoField.Text = dataReader["OD"].ToString();
PdLocField.Text = dataReader["pd"].ToString();
StatementNoField.Text = dataReader["Statmnt"].ToString();
ApplicationNoField.Text = dataReader["AppNo"].ToString();
AppDateField.Text = dataReader["AppDate"].ToString();
areaField.Text = dataReader["Area"].ToString();
areaNoField.Text = dataReader["AreaNo"].ToString();
blockNoField.Text = dataReader["BlockNo"].ToString();
streetNoField.Text = dataReader["StreetNo"].ToString();
}
}
}
}
catch (Exception ex)
{
HttpContext.Current.Response.Write("No Connection!!");
}
finally
{
sqlConn.Close();
}
In addition to this question: Preorder tree traversal copy folder
I was wondering if it is possible to create a transaction that contains different calls to the database.
ex:
public bool CopyNode(int nodeId, int parentNode)
{
// Begin transaction.
try
{
Method1(nodeId);
Method2(nodeId, parentNode);
Method3(nodeId);
}
catch (System.Exception ex)
{
//rollback all the methods
}
}
I don't know if this is possible. We are using subsonic to do the database calls.
This is really important, not only for the tree traversal problem but also for some other stuff we do.
The main idea is that we can't let our dabase get corrupted with uncomplete data.
That is possible, you can find a example here
Or perhaps a transaction scope...
http://msdn.microsoft.com/en-us/library/ms172152.aspx
BeginTransaction is called off a ADO.NET collection object.
The Command object needs this transaction (SqlTransaction object) assigned to it.
Commit and Rollback are only called in the outer method.
Check out this code. It works by re-using the SqlConnection and SqlTransaction objects. This is a classic Master>Details type of set up. The master type is ColumnHeaderSet which contains a property of
List<ColumnHeader>
, which is the details (collection).
Hope this helps.
-JM
public static int SaveColumnHeaderSet(ColumnHeaderSet set)
//save a ColumnHeaderSet
{
string sp = ColumnSP.usp_ColumnSet_C.ToString(); //name of sp we're using
SqlCommand cmd = null;
SqlTransaction trans = null;
SqlConnection conn = null;
try
{
conn = SavedRptDAL.GetSavedRptConn(); //get conn for the app's connString
cmd = new SqlCommand(sp, conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
trans = conn.BeginTransaction();
cmd.Transaction = trans; // Includes this cmd as part of the trans
//parameters
cmd.Parameters.AddWithValue("#ColSetName", set.ColSetName);
cmd.Parameters.AddWithValue("#DefaultSet", 0);
cmd.Parameters.AddWithValue("#ID_Author", set.Author.UserID);
cmd.Parameters.AddWithValue("#IsAnonymous", set.IsAnonymous);
cmd.Parameters.AddWithValue("#ClientNum", set.Author.ClientNum);
cmd.Parameters.AddWithValue("#ShareLevel", set.ShareLevel);
cmd.Parameters.AddWithValue("#ID_Type", set.Type);
//add output parameter - to return new record identity
SqlParameter prm = new SqlParameter();
prm.ParameterName = "#ID_ColSet";
prm.SqlDbType = SqlDbType.Int;
prm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(prm);
cmd.ExecuteNonQuery();
int i = Int32.Parse(cmd.Parameters["#ID_ColSet"].Value.ToString());
if (i == 0) throw new Exception("Failed to save ColumnHeaderSet");
set.ColSetID = i; //update the object
//save the ColumnHeaderList (SetDetail)
if (ColumnHeader_Data.SaveColumnHeaderList(set, conn, trans)==false) throw new Exception("Failed to save ColumnHeaderList");
trans.Commit();
// return ID for new ColHdrSet
return i;
}
catch (Exception e){
trans.Rollback();
throw e;
}
finally{
conn.Close();
}
}
public static bool SaveColumnHeaderList(ColumnHeaderSet set, SqlConnection conn, SqlTransaction trans)
//save a (custom)ColHeaderList for a Named ColumnHeaderSet
{
// we're going to accept a SqlTransaction to maintain transactional integrity
string sp = ColumnSP.usp_ColumnList_C.ToString(); //name of sp we're using
SqlCommand cmd = null;
try
{
cmd = new SqlCommand(sp, conn); // re-using the same conection object
cmd.CommandType = CommandType.StoredProcedure;
cmd.Transaction = trans; // includes the cmd in the transaction
//build params collection (input)
cmd.Parameters.Add("#ID_ColSet", SqlDbType.Int);
cmd.Parameters.Add("#ID_ColHeader", SqlDbType.Int);
cmd.Parameters.Add("#Selected", SqlDbType.Bit);
cmd.Parameters.Add("#Position", SqlDbType.Int);
//add output parameter - to return new record identity
//FYI - #return_value = #ID_SavedRpt
SqlParameter prm = new SqlParameter();
prm.ParameterName = "#ID";
prm.SqlDbType = SqlDbType.Int;
prm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(prm);
//Loop
foreach (ColumnHeader item in set.ColHeaderList)
{
//set param values
cmd.Parameters["#ID_ColSet"].Value = set.ColSetID;
cmd.Parameters["#ID_ColHeader"].Value = item.ColHeaderID;
cmd.Parameters["#Selected"].Value = item.Selected;
cmd.Parameters["#Position"].Value = item.Position;
cmd.ExecuteNonQuery();
int i = Int32.Parse(cmd.Parameters["#ID"].Value.ToString());
if (i == 0) throw new Exception("Failed to save ColumnHeaderSet");
}
return true;
}
catch (Exception e)
{
throw e;
}
}