Pass parameters correctly to SqlCommand - c#

I have code to insert data to SQL table.
The columns have such types:
#param1 datetime,
#param2 nvarchar(50),
#param3 int,
#param4 bit,
#param5 int,
#param6 bit,
#param7 bit,
#param8 varchar(20),
#param9 varchar(20)
This is my method:
try
{
using (SqlCommand oleDbCommand = new SqlCommand())
{
// Set the command object properties
oleDbCommand.Connection = new SqlConnection(connectionString);
oleDbCommand.CommandType = CommandType.StoredProcedure;
oleDbCommand.CommandText = "[dbo].[InsertRow]";
// Add the input parameters to the parameter collection
// m.param1 is of DateTime type, m.param2 of string type, m.param3 of int type, etc.
oleDbCommand.Parameters.AddWithValue("#param1", m.param1);
oleDbCommand.Parameters.AddWithValue("#param2", m.param2);
oleDbCommand.Parameters.AddWithValue("#param3", m.param3);
oleDbCommand.Parameters.AddWithValue("#param4", m.param4);
oleDbCommand.Parameters.AddWithValue("#param5", m.param5);
oleDbCommand.Parameters.AddWithValue("#param6", m.param6);
oleDbCommand.Parameters.AddWithValue("#param7", m.param7);
oleDbCommand.Parameters.AddWithValue("#param8", m.param8);
oleDbCommand.Parameters.AddWithValue("#param9", m.param9);
// Open the connection, execute the query and close the connection.
oleDbCommand.Connection.Open();
oleDbCommand.ExecuteNonQuery();
oleDbCommand.Connection.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
I have two but related questions:
am I passing parameters correctly? Or do I need casts? (please see the column types in the
beginning of the question).
how to correctly handle closing of database? In case also of some exception?

I would do as below
try
{
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand("[dbo].[InsertRow]", conn) {
CommandType = CommandType.StoredProcedure }) {
conn.Open();
command.Parameters.Add("#param1", SqlDbType.DateTime).Value = m.param1;
command.Parameters.Add("#param2", SqlDbType.NVarChar, 50).Value = m.param2;
command.Parameters.Add("#param3", SqlDbType.Int).Value = m.param3;
command.Parameters.Add("#param4", SqlDbType.Bit).Value = m.param4;
command.Parameters.Add("#param5", SqlDbType.Int).Value = m.param5;
command.Parameters.Add("#param6", SqlDbType.Bit).Value = m.param6;
command.Parameters.Add("#param7", SqlDbType.Bit).Value = m.param7;
command.Parameters.Add("#param8", SqlDbType.VarChar, 20).Value = m.param8;
command.Parameters.Add("#param9", SqlDbType.VarChar, 20).Value = m.param9;
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}

AddWithValue tries to assigns the value by unboxing an object in the c# type based on the database field's type.
try
{
using (var oleDbConnection = new SqlConnection(connectionString))
{
// Set the command object properties
SqlCommand oleDbCommand = new SqlCommand()
oleDbCommand.Connection = oleDbConnection;
oleDbCommand.CommandType = CommandType.StoredProcedure;
oleDbCommand.CommandText = "[dbo].[InsertRow]";
// Add the input parameters to the parameter collection
// m.param1 is of DateTime type, m.param2 of string type, m.param3 of int type, etc.
oleDbCommand.Parameters.AddWithValue("#param1", m.param1);
oleDbCommand.Parameters.AddWithValue("#param2", m.param2);
oleDbCommand.Parameters.AddWithValue("#param3", m.param3);
oleDbCommand.Parameters.AddWithValue("#param4", m.param4);
oleDbCommand.Parameters.AddWithValue("#param5", m.param5);
oleDbCommand.Parameters.AddWithValue("#param6", m.param6);
oleDbCommand.Parameters.AddWithValue("#param7", m.param7);
oleDbCommand.Parameters.AddWithValue("#param8", m.param8);
oleDbCommand.Parameters.AddWithValue("#param9", m.param9);
// Open the connection, execute the query and close the connection.
oleDbCommand.Connection.Open();
oleDbCommand.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
using statement adds itself the correct connection handling after its use.

Related

Convert Command.ExecuteScalar() To Int

I need to insert a line in my question table and retrieve the inserted id. I initialize my sql command and execute it with ExecuteScalar(). I'm trying to convert the result of this method to int but I can not do it.
I tried to do that:
int result = Convert.ToInt32(Command.ExecuteScalar));
or
int result = (int)Command.ExecuteScalar();
but nothing work
here is my function
public int AddQuestionOrientation(Question questionForAdd)
{
try
{
con = new SqlConnection(connectionString);
con.Open();
SqlCommand command;
String sql = "";
sql = "INSERT INTO QUESTION VALUES(#Libelle,
#Bareme,2,#Filliere)";
SqlParameter param = new SqlParameter();
param.ParameterName = "#Libelle";
param.Value = questionForAdd.Libelle;
SqlParameter param2 = new SqlParameter();
param2.ParameterName = "#Bareme";
param2.Value = questionForAdd.Bareme;
SqlParameter param3 = new SqlParameter();
param3.ParameterName = "#Filliere";
param3.Value = questionForAdd.IdFiliere;
command = new SqlCommand(sql, con);
command.Parameters.Add(param);
command.Parameters.Add(param2);
command.Parameters.Add(param3);
int idQuestionInserted = (int)command.ExecuteScalar();
command.Dispose();
con.Close();
return idQuestionInserted;
}
catch(Exception ex)
{
return 0;
}
}
If I try with the cast (int), I have the message error:
Object reference not set to an instance of an object
If I try with the Convert.ToInt32, my variable "IdQuestionInserted" is equal to 0.
This is a big departure from where you started. But you have several issue going on there. You should use the USING statement around objects with the IDisposable interface (connections, commands, etc...).
This code is all untested but should be really close.
Start with creating a stored procedure so you can start creating layers in your application.
create Procedure Question_Insert
(
#Libelle varchar(50)
, #Bareme varchar(50)
, #Filliere varchar(50)
, #QuestionID int output
) as
set nocount on;
INSERT INTO QUESTION
(
Libelle
, Bareme
, Filliere
)
values
(
#Libelle
, #Bareme
, #Filliere
)
select #QuestionID = SCOPE_IDENTITY()
Then in your dotnet code you need to change up a few things to make it cleaner and more robust. Ideally you should do something better than simply return 0 when there is an error. It will be really tough to debug when something goes wrong if you simply return a 0. This is like an error message that says, "An error occurred". Pretty useless. Do something with the error. Capture the message to enable you to fix it.
public int AddQuestionOrientation(Question questionForAdd)
{
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlCommand command = new SqlCommand("Question_Insert"))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#Libelle", SqlDbType.VarChar, 50).Value = questionForAdd.Libelle;
command.Parameters.Add("#Bareme", SqlDbType.VarChar, 50).Value = questionForAdd.Bareme;
command.Parameters.Add("#Filliere", SqlDbType.VarChar, 50).Value = questionForAdd.IdFiliere;
command.Parameters.Add("#QuestionID", SqlDbType.Int).Direction = ParameterDirection.Output;
command.ExecuteNonQuery();
return int.Parse(command.Parameters["#QuestionID"].Value.ToString());
}
}
}
catch (Exception ex)
{
return 0;
}
}
To get inserted id use SCOPE_IDENTITY() add SELECT CAST(scope_identity() AS int to command query to do
INSERT INTO QUESTION
VALUES(#Libelle, #Bareme, 2, #Filliere);
SELECT CAST(scope_identity() AS int;
this query will return inserted id for you.

C# Oracle - Execute Stored Procedures in sequence

Hi guys I'm having troubles trying execute Stored procedures on cascade, I need some help. Let's see the scenario:
I have a father table, let's call it "REQUEST" and a child table, "REQUEST_DETAILS"
Now from C# I know how to execute an Oracle SP, but I donĀ“t know how to execute two in a chain, without commit until the end of all.
I need to insert the father table data and after get the generated REQUEST.ID to start to insert the children data with the REQUEST.ID
So the first stored procedure will insert the REQUEST data and the second one will insertrt the REQUEST_DETAIL data but if something goes wrong I want to rollback all the transactions.
There is a way to do this of a simple way ?
Here is my code any help will be usefull.
public Bool SaveRequest(Request newRequestData)
{
var connection = new connection();
bool isSuccess = true;
OracleConnection Conn = connection._GetInstance();
OracleCommand Cmd = new OracleCommand();
Conn.Open();
Cmd.Connection = Conn;
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.CommandText = "PackageRequests.InsertNewRequest";
Cmd.BindByName = true;
//IN PARAM
Cmd.Parameters.Add(new OracleParameter("P_LOCATION", OracleDbType.Varchar2, newRequestData.location, ParameterDirection.Input));
Cmd.Parameters.Add(new OracleParameter("P_PCSTOTAL", OracleDbType.Int32, newRequestData.pcsTotal, ParameterDirection.Input));
Cmd.Parameters.Add(new OracleParameter("P_STATUS", OracleDbType.Int32, newRequestData.status, ParameterDirection.Input));
//Out Param
Cmd.Parameters.Add(new OracleParameter("P_NEW_ID", OracleDbType.Int32)).Direction = ParameterDirection.Output;
OracleTransaction transaction = Conn.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
Cmd.ExecuteNonQuery();
//New request_id
string newId = Convert.ToString(Cmd.Parameters["P_NEW_ID"].Value);
//Here I think goes the logic for execute the another procedure that will insert the data into REQUEST_DETAIL
/***
foreach(var item in newRequestData.List)
{
//Insert request_detail_Data()
}
***/
//after all -- transaction.Commit();
}
catch (OracleException ex)
{
//If something goes wrong rollback.
transaction.Rollback();
isSuccess = false;
}
finally
{
Conn.Close();
}
return isSuccess;
}
I found the solution to do this the trick is on pass the Oracle Connection like parameter to the another functions and when all is done commit and if something fails rollback, from the initial function. I leave an example I hope will be helpful for someone.
public Bool SaveRequest(Request newRequestData)
{
var connection = new connection();
bool isSuccess = true;
OracleConnection Conn = connection._GetInstance();
OracleCommand Cmd = new OracleCommand();
Conn.Open();
Cmd.Connection = Conn;
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.CommandText = "PackageRequests.InsertNewRequest";
Cmd.BindByName = true;
// IN PARAMETERS...
Cmd.Parameters.Add(new OracleParameter("P_LOCATION", OracleDbType.Varchar2, newRequestData.location, ParameterDirection.Input));
// OUT PARAMETER (Here I recover the master table ID)
Cmd.Parameters.Add(new OracleParameter("P_NEW_ID", OracleDbType.Int32)).Direction = ParameterDirection.Output;
// Initialize the Transaction
OracleTransaction transaction = Conn.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
//Execute the first SP
Cmd.ExecuteNonQuery();
string newId = Convert.ToString(Cmd.Parameters["P_NEW_ID"].Value);
// Calls another function and pass Oracle Connection, and master table ID like parameters
InsertRequestDetail(Conn, newId);
transaction.Commit();
}
catch (OracleException ex)
{
//If something goes wrong rollback.
transaction.Rollback();
isSuccess = false;
}
finally
{
Conn.Close();
}
return isSuccess;
}
private void InsertRequestDetail(OracleConnection Conn, string newId)
{
OracleCommand Cmd = new OracleCommand();
Cmd.Connection = Conn;
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.CommandText = "MY_PACKAGE.AnotherSPName";
Cmd.BindByName = true;
//IN - OUT PARAMS
Cmd.Parameters.Add(new OracleParameter("...
Cmd.ExecuteNonQuery();
}

C# update and set of database (datediff) don't work when in C# but works if in SQL Server

I have searched for solutions but I can't find one; please help.
I have this code fragment in C#:
using (SqlCommand command = new SqlCommand())
{
command.Connection = openCon;
command.CommandType = CommandType.Text;
command.CommandText = "update logRecords set totalHours = DATEDIFF(HOUR,timeIn,timeOut)";
try
{
openCon.Open();
int recordsAffected = command.ExecuteNonQuery();
MessageBox.Show("Records affected: " + recordsAffected);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
openCon.Close();
GetLogData();
}
}
but it doesn't work. It didn't show the message box in the try block neither the one in the catch block.
Thanks for helping :D
You can access query with parameters, hope this help:
using(var openCon = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand())
{
command.Connection = openCon;
command.CommandType = CommandType.Text;
command.CommandText = "update logRecords set totalHours = DATEDIFF(HOUR,#timeIn,#timeOut)";
try
{
openCon.Open();
command.Parameters.AddWithValue("#timeIN", timeIn);
command.Parameters.AddWithValue("#timeOut", timeOut);
int recordsAffected = command.ExecuteNonQuery();
MessageBox.Show("Records affected: " + recordsAffected);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
GetLogData();
}
First of all I will create Stored procedure and I will update any of my table through procedure.
So, Basic SP will be like below, and I will run it in a Database(SQL).
CREATE PROCEDURE Set_LogRecords_TotalHours
-- Add the parameters for the stored procedure here
#timeIn datetime,
#timeOut datetime
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
UPDATE LogRecords
SET TotalHours = DATEDIFF(HOUR, #timeIn, #timeOut)
-- returns number of rows
SELECT ##ROWCOUNT
END
GO
Now, I will Move to code side.
I will Create a Generic method to call All of mine Stored procedures, see below.
public static DataSet GetRecordWithExtendedTimeOut(string SPName, params SqlParameter[] SqlPrms)
{
DataSet ds = new DataSet();
try
{
//here give reference of your connection and that is "openCon"
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(SPName, conn))
{
command.Parameters.AddRange(SqlPrms);
command.CommandTimeout = 0;
conn.Open();
command.CommandType = CommandType.StoredProcedure;
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
{
try
{
dataAdapter.SelectCommand = command;
dataAdapter.Fill(ds);
}
catch (Exception ex)
{
return null;
}
finally
{
conn.Close();
}
}
}
}
}
catch (Exception ex)
{
//Handle Errror
}
return ds;
}
Now at last, call this method from wherever you need to access database.
Over here is the example of calling generic method.
//Add all the parameter that you want to pass to SP, here we have 2 and they are in DAteTime Formate
SqlParameter[] parameters =
{
new SqlParameter { ParameterName = "#timeIn", Value = ValueOf_TimeIN_DateTIME }
new SqlParameter { ParameterName = "#timeOut", Value = ValueOf_TimeOUT__DateTIME}
};
DataSet ds = DAL.GetRecordWithExtendedTimeOut("Set_LogRecords_TotalHours", parameters);
if (ds != null && ds.Tables.Count >= 1 && ds.Tables[0].Rows.Count >= 1)
{
//Debugg ds and you will see the number of records that affected in last update
}

Windows Form SqlCommand C# Error

I have a Windows Forms program I was writing at home (I mostly work with ASP.Net so it's been a while) and I'm having trouble executing stored procedure commands.
I create the SqlCommand object from the SqlConnection object and then create the SqlParameter from the SqlCommand. I specify the name, data type, and so on. However, whenever I call SqlCommand ExecuteReader() it's telling me it expects parameters that were not provided. I clearly added them and can see them populated when stepping through in Debug. Any ideas?
Stored procedure:
EXEC dbo.GetTransactions #StartDate = '2015-04-10 18:07:43',
#EndDate = '2015-04-10 18:07:43'
Class DataAccess:
public static DataTable Execute(SqlCommand iCommand) {
DataTable objTable = new DataTable();
try {
iCommand.Connection.Open();
SqlDataReader objReader = iCommand.ExecuteReader();
objTable.Load(objReader);
objReader.Close();
}
catch {
throw;
}
finally {
iCommand.Connection.Close();
}
return objTable;
}
public static SqlCommand CreateCommand(string iProcedureName) {
try {
SqlConnection objConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["DBConnectionString"].ToString());
SqlCommand objCommand = new SqlCommand(iProcedureName, objConnection);
return objCommand;
}
catch {
throw;
}
}
Class TransactionCollection:
private static DataTable Load(DateTime iStartDate, DateTime iEndDate) {
string strProcedureName = "GetTransactions";
SqlCommand objCommand = DataAccess.CreateCommand(strProcedureName);
SqlParameter param = objCommand.CreateParameter();
param.ParameterName = "#StartDate";
param.DbType = DbType.DateTime;
param.Value = iStartDate;
objCommand.Parameters.Add(param);
param = objCommand.CreateParameter();
param.ParameterName = "#EndDate";
param.DbType = DbType.DateTime;
param.Value = iEndDate;
objCommand.Parameters.Add(param);
return DataAccess.Execute(objCommand);
}
You need to tell your SqlCommand that it's executing a stored procedure! You need to set the CommandType of your SqlCommand - see here:
public static SqlCommand CreateCommand(string iProcedureName) {
try {
SqlConnection objConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["DBConnectionString"].ToString());
SqlCommand objCommand = new SqlCommand(iProcedureName, objConnection);
// add this line here!!
objCommand.CommandType = CommandType.StoredProcedure;
return objCommand;
}
catch {
throw;
}
}

Inserting an E notation double into a decimal column

I have a number in C# which is double longitude =1.041970849797e-05.
When I try to insert it into a decimal(9,6) column, I get the error message:
Error converting data type nvarchar to numeric
How do I correctly save the above as a decimal?
C# Application Code:
static void Main(string[] args)
{
double lat=1.041970849797e-05;
insertRecs(lat);
}
private static void insertRecs(double latitude)
{
Int32 rowsAffected = 0;
string connectionString = GetConnectionString();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand cmd = new SqlCommand("dbo.usp_temp", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 90;
try
{
rowsAffected = cmd.ExecuteNonQuery();
}
catch (Exception ep)
{
Console.WriteLine("Exception in Insertrecords ");
Console.WriteLine(ep.Message);
}
}
}
SQL Stored Procedure:
create PROCEDURE [dbo].[usp_temp]
--The parameters for the stored procedure
#latitude decimal(9,6)
AS
BEGIN
insert into temptest(latitude) values(#latitude);
END
Looking at the sample of code you gave us you don't actually map the latitude variable when running the Stored Procedure.
You would need to add a couple of lines like so:
SqlParameter param = cmd.Parameters.Add("#latitude", SqlDbType.Decimal);
param.Direction = ParameterDirection.Input;
param.Value = latitude;
And edited into your code:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand cmd = new SqlCommand("dbo.usp_temp", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 90;
// Map the parameters into the Stored Procedure
SqlParameter param = cmd.Parameters.Add("#latitude", SqlDbType.Decimal);
param.Direction = ParameterDirection.Input;
param.Value = latitude;
try
{
rowsAffected = cmd.ExecuteNonQuery();
}
catch (Exception ep)
{
Console.WriteLine("Exception in Insertrecords ");
Console.WriteLine(ep.Message);
}
}

Categories