Using Rollback transaction with datatable sql - c#

My project works properly but my issue is when there's an error occured in the second SP spInsertCorpPlan there is no value inserted in CorporationPlan while there is a value inserted in First table CorporationContact.
How to Rollback this.?
Please help.
for (int row = 0; row < dtContact.Rows.Count; row++)
{
SqlCommand cmdContact = new SqlCommand("_spInsertCorpContact", _DentalConOpen());
cmdContact.CommandType = CommandType.StoredProcedure;
cmdContact.Parameters.Add("#CorpCode", SqlDbType.VarChar).Value = Corporation.CorpCode;
cmdContact.Parameters.Add("#ContactType", SqlDbType.VarChar).Value = dtContact.Rows[row][0].ToString();
cmdContact.Parameters.Add("#AreaCode", SqlDbType.VarChar).Value = dtContact.Rows[row][1].ToString();
cmdContact.Parameters.Add("#ContactNo", SqlDbType.VarChar).Value = dtContact.Rows[row][2].ToString();
cmdContact.Parameters.Add("#User", SqlDbType.VarChar).Value = Corporation.User;
cmdContact.ExecuteNonQuery();
cmdContact.Dispose();
cmdContact.Connection.Close();
}
for (int row = 0; row < dtPlan.Rows.Count; row++)
{
SqlCommand cmdPlan = new SqlCommand("_spInsertCorpPlan", _DentalConOpen());
cmdPlan.CommandType = CommandType.StoredProcedure;
cmdPlan.Parameters.Add("#CorpCode", SqlDbType.VarChar).Value = Corporation.CorpCode;
cmdPlan.Parameters.Add("#PlanID", SqlDbType.VarChar).Value = dtPlan.Rows[row][0].ToString();
cmdPlan.Parameters.Add("#EffectiveDate", SqlDbType.DateTime).Value = Convert.ToDateTime(dtPlan.Rows[row][2]);
cmdPlan.Parameters.Add("#ExpiryDate", SqlDbType.DateTime).Value = Convert.ToDateTime(dtPlan.Rows[row][3]);
cmdPlan.Parameters.Add("#User", SqlDbType.VarChar).Value = Corporation.User;
cmdPlan.ExecuteNonQuery();
cmdPlan.Dispose();
cmdPlan.Connection.Close();
}
My Stored Procedures:
ALTER PROCEDURE [dbo].[_spInsertCorpContact]
#CorpCode varchar(20),
#ContactType varchar(1),
#AreaCode varchar(10),
#ContactNo varchar(20),
#User varchar (50)
AS
BEGIN
Insert into CorporationContact
(CorpCode,
ContactType,
AreaCode,
ContactNo,
CreateBy,
CreateDate,
UpdateBy,
UpdateDate)
values
(#CorpCode,
#ContactType,
#AreaCode,
#ContactNo,
#User,
GETDATE(),
'',
null
)
END
ALTER PROCEDURE [dbo].[_spInsertCorpPlan]
#CorpCode varchar(20),
#PlanID varchar(20),
#EffectiveDate DATETIME,
#ExpiryDate DATETIME,
#User varchar (50)
AS
BEGIN
Insert into CorporationPlan
(CorporationPlanID,
CorpCode,
PlanCode,
EffectiveDate,
ExpiryDate,
CreateBy,
CreateDate,
UpdateBy,
UpdateDate)
values
(#CorpCode+#PlanID,
#CorpCode,
#PlanID,
#EffectiveDate,
#ExpiryDate,
#User,
GETDATE(),
'',
null
)
END

You can use SqlTransaction to achieve this. See the sample on this MSDN page. However, make sure you the right isolation level otherwise you might end up creating deadlocks.
Essentially, your code would look something like this:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var transaction = connection.BeginTransaction();
try
{
// Initialize and execute the first command
SqlCommand command = GetFirstCommand();
command.Connection = connection;
command.ExecuteNonQuery();
// Initialize and execute the first command
command = GetSecondCommand();
command.Connection = connection;
command.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw;
}
}

Related

Procedure or function Proc_PIP_Employee has too many arguments specified

I am getting error
Procedure or function Proc_PIP_Employee has too many arguments specified
when trying to call procedure Proc_PIP_Employee from C# code. The count of parameters checked and those are same. Also datatypes are same. Even after that getting the same error.
C# code is
public int Add_Record(Employee emp)
{
try
{
if (con.State != ConnectionState.Open)
con.Open();
using (SqlCommand cmd = con.CreateCommand())
{
SqlParameter RETURN_VALUE_OUTPUT = new SqlParameter();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.Proc_PIP_Employee";
cmd.Parameters.Add("#Flag", SqlDbType.Int).Value = 1;
cmd.Parameters.Add("#Empid", SqlDbType.Int).Value = 0;
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = emp.Name ;
cmd.Parameters.Add("#Designation", SqlDbType.VarChar).Value = emp.Designation;
cmd.Parameters.Add("#Department", SqlDbType.VarChar).Value = emp.Department;
cmd.Parameters.Add("#DateofJoin", SqlDbType.DateTime).Value = emp.Dateofjoin;
cmd.Parameters.Add("#Phone", SqlDbType.VarChar).Value = emp.Phone;
cmd.Parameters.Add("#Isactive", SqlDbType.Int).Value = emp.IsActive;
cmd.Parameters.Add("#LoginUser", SqlDbType.NVarChar).Value = "admin";
RETURN_VALUE_OUTPUT = cmd.Parameters.Add("#ReturnId",SqlDbType.Int);
RETURN_VALUE_OUTPUT.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
ReturnID = Convert.ToInt32(RETURN_VALUE_OUTPUT.Value.ToString());
}
}
catch (SqlException ex)
{
}
return ReturnID;
}
The stored procedure is:
ALTER PROCEDURE [dbo].[Proc_PIP_Employee]
#Flag int,
#Empid int,
#Name varchar(500),
#Designation varchar(200),
#Department varchar(200),
#DateofJoin datetime,
#Phone varchar(3000),
#Isactive int,
#LoginUser nvarchar(500)
AS
BEGIN
SET NOCOUNT ON ;
DECLARE #errorMessage VarChar(8000),
#errorSeverity Int,
#errorState Int,
#ReturnId Int,
#AlCode varchar(50),
#AlDesc varchar(1000),
#AlOp varchar(50),
#AlStatus varchar(50)
BEGIN TRY
BEGIN TRANSACTION
IF (#Flag = 1)
BEGIN
IF EXISTS (SELECT 1 FROM dbo.PIP_Employee
GROUP BY Name, Phone
You're adding an OUTPUT parameter for this stored procedure to your C# code - but there's no #ReturnId OUTPUT parameter in your stored procedure interface:
SqlParameter RETURN_VALUE_OUTPUT = new SqlParameter();
RETURN_VALUE_OUTPUT = cmd.Parameters.Add("#ReturnId",SqlDbType.Int);
RETURN_VALUE_OUTPUT.Direction = ParameterDirection.Output;
If you attempted to capture the return value - then use ParameterDirection.ReturnValue instead
SqlParameter RETURN_VALUE_OUTPUT = new SqlParameter();
RETURN_VALUE_OUTPUT = cmd.Parameters.Add("#ReturnId",SqlDbType.Int);
RETURN_VALUE_OUTPUT.Direction = ParameterDirection.ReturnValue;

Unable to Update Rows in a SQL Table

I have some code that inserts and updates data into a sql table. I use ExecuteScalar to check if a row already exists with the same UserName and DeviceId. If it exists, we run the update stored procedure, overriding the DataSource, PendingCount and LastUpdated fields. If the row doesn't exist, we use the insert stored procedure. The insert stored procedure works great, but the update stored procedure doesn't seem to do anything. The row remains the same. Here is the code in question:
try
{
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
using (SqlCommand comm = new SqlCommand(query, sqlConnection))
{
comm.CommandType = System.Data.CommandType.Text;
comm.Parameters.Add(new SqlParameter("#DataSource", pending.DataSource));
comm.Parameters.Add(new SqlParameter("#LastUpdated", pending.LastUpdated));
comm.Parameters.Add(new SqlParameter("#PendingCount", pending.PendingCount));
comm.Parameters.Add(new SqlParameter("#DeviceId", pending.DeviceId));
comm.Parameters.Add(new SqlParameter("#UserName", pending.UserName));
int rowCount = (int)comm.ExecuteScalar();
if (rowCount > 0)
{
using (SqlCommand sqlComm = new SqlCommand("sp_UpdatePendingAttachments", sqlConnection))
{
sqlComm.CommandType = System.Data.CommandType.Text;
sqlComm.Parameters.Add(new SqlParameter("#DataSource", pending.DataSource));
sqlComm.Parameters.Add(new SqlParameter("#LastUpdated", pending.LastUpdated));
sqlComm.Parameters.Add(new SqlParameter("#PendingCount", pending.PendingCount));
sqlComm.Parameters.Add(new SqlParameter("#DeviceId", pending.DeviceId));
sqlComm.Parameters.Add(new SqlParameter("#UserName", pending.UserName));
}
}
else
{
using (SqlCommand sqlCommand = new SqlCommand("sp_InsertPendingAttachments", sqlConnection))
{
sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
sqlCommand.Parameters.Add(new SqlParameter("#DataSource", pending.DataSource));
sqlCommand.Parameters.Add(new SqlParameter("#UserName", pending.UserName));
sqlCommand.Parameters.Add(new SqlParameter("#DeviceId", pending.DeviceId));
sqlCommand.Parameters.Add(new SqlParameter("#PendingCount", pending.PendingCount));
sqlCommand.Parameters.Add(new SqlParameter("#LastUpdated", pending.LastUpdated));
sqlCommand.ExecuteNonQuery();
}
}
}
}
return new BaseResponse();
}
The stored procedure for updating is "sp_UpdateStoredProcedure":
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_UpdatePendingAttachments]
(
-- Add the parameters for the stored procedure here
#DataSource VARCHAR(150) = '',
#DeviceId VARCHAR(150) = '',
#UserName VARCHAR(150) = '',
#PendingCount int = null,
#LastUpdated DateTime = null
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
-- Insert statements for procedure here
UPDATE PendingAttachments
SET DataSource = #DataSource, PendingItemsCount = #PendingCount, LastUpdated = #LastUpdated
WHERE DeviceId = #DeviceId AND UserName = #UserName
END
GO
Any idea why updating rows isn't working? Is it a problem with the stored procedure, or the c# code? Any feedback is appreciated!
You need to use some execution method on the mentioned place in the attached image to execute your Transact-SQL statement.
You have used ExecuteScaler() once to figure out the existing record but at the time of updation you have missed adding any execution method.

How can I solve this error "Does not allow NULL, Insert Aborted"?

I'm trying to call a stored procedure to make an insert:
private void button1_Click(object sender, EventArgs e)
{
string connectionString = #"Data Source=******;Initial Catalog=**********;Integrated Security=True";
using (SqlConnection sqlCon = new SqlConnection(connectionString: connectionString))
{
using (SqlCommand cmd = new SqlCommand("InsertAngajat", sqlCon))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Nume", SqlDbType.VarChar).Value = textBox1.Text;
cmd.Parameters.Add("#Prenume", SqlDbType.VarChar).Value = textBox2.Text;
cmd.Parameters.Add("#DataNasterii", SqlDbType.Date).Value = textBox4.Text;
cmd.Parameters.Add("#DataAngajare", SqlDbType.Date).Value = DateTime.Today.ToString();
cmd.Parameters.Add("#cnp", SqlDbType.Char).Value = textBox3.Text.ToCharArray();
cmd.Parameters.Add("#Localitate", SqlDbType.VarChar).Value = textBox8.Text;
cmd.Parameters.Add("#Judet", SqlDbType.VarChar).Value = textBox10.Text;
cmd.Parameters.Add("#Strada", SqlDbType.VarChar).Value = textBox9.Text;
cmd.Parameters.Add("#Departament", SqlDbType.VarChar).Value = comboBox1.Text;
cmd.Parameters.Add("#Telefon", SqlDbType.Char).Value = textBox5.Text.ToCharArray();
if (checkBox1.Checked)
cmd.Parameters.Add("#Sex", SqlDbType.Char).Value = 'M';
else if (checkBox2.Checked)
cmd.Parameters.Add("#Sex", SqlDbType.Char).Value = 'F';
else
MessageBox.Show("Nu a fost bifat sexul");
cmd.Parameters.Add("#Numar", SqlDbType.Int).Value = Convert.ToInt32(textBox11.Text);
cmd.Parameters.Add("#Salariu", SqlDbType.Int).Value = Convert.ToInt32(textBox6.Text);
sqlCon.Open();
cmd.ExecuteNonQuery();
}
}
this.Close();
}
But this is the error I get when I press the button and save everything.
https://i.imgur.com/0tixhsu.png
This is the SQL Server stored procedure:
ALTER PROCEDURE [dbo].[InsertAngajat]
#Nume VARCHAR(50),
#Prenume VARCHAR(50),
#Departament VARCHAR(50),
#cnp CHAR(13),
#DataNasterii DATE,
#Telefon VARCHAR(12) = "NONE",
#DataAngajare DATE,
#Salariu INT,
#Sex CHAR(1) = 'F',
#Judet VARCHAR(50),
#Localitate VARCHAR(50),
#Strada VARCHAR(50),
#Numar INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #DepID INT = (SELECT D.DepartamentID
FROM Departamente D
WHERE D.[Nume Departament] = #Departament);
INSERT INTO [dbo].Angajat (Nume, Prenume, DepartamentID, CNP, DataNasterii,
Telefon, DataAngajarii, Salariu, Sex, Localitate,
[Sector/Judet], Strada, nr)
VALUES (#Nume, #Prenume, #DepID, #cnp, #DataNasterii,
#Telefon, #DataAngajare, #Salariu, #Sex, #Localitate,
#Judet, #Strada, #Numar)
END
I made sure that the text boxes were having data. I have no idea what else to try.
I'm expecting that as long as the values in the text boxes aren't NULL to be able to Insert all their data easily.
It seems to me that your issue probably lies with this line:
Declare #DepID int = (Select D.DepartamentID From Departamente D Where D.[Nume Departament] = #Departament);
What happens if there are no results for this query? I'm a bit rusty, but I imagine #DepId will be NULL. Then when you try and insert it into your table, you're inserting a null.
Solution: Either in your procedure, or before calling the insert, check if the department exists.
Run your sql profiler and trace the call. So that, you will be sure about your all input parameters. And then execute your procedure call manually. You will be able to find the exact issue and the line in the procedure. Try one with fixed value of #DepID int=1. If it's running successfully. Then you have to optimized this line of code as below:
Declare #DepID int = (Select isnull(D.DepartamentID,0) From Departamente D Where D.[Nume Departament] = #Departament);
It seems your Departamente table don't have data for this department.

Sqlparameter should be assigned Exception and if I assigned so,there is violation of primary key constraint exception

I have to insert the field values but not the id which is a primary key and set identity(1,1). Stored Procedure is also added at the bottom.
protected void save_click(object sender, EventArgs e)
{
con = new SqlConnection(s);
con.Open();
cmd = new SqlCommand("employeedtl", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#empname", SqlDbType.VarChar).Value = TextBox1.Text;
cmd.Parameters.Add("#empid", SqlDbType.Int).Value = int.Parse(TextBox2.Text);
cmd.Parameters.Add("#empage", SqlDbType.Int).Value = int.Parse(TextBox3.Text);
cmd.Parameters.Add("#empaddress", SqlDbType.VarChar).Value = TextBox4.Text;
cmd.Parameters.Add("#empjoindate", SqlDbType.VarChar).Value = TextBox5.Text;
cmd.Parameters.Add("#empproject", SqlDbType.VarChar).Value = TextBox6.Text;
cmd.Parameters.Add("#empmobile", SqlDbType.BigInt).Value = Int64.Parse(TextBox7.Text);
cmd.Parameters.Add("#empemail", SqlDbType.VarChar).Value = TextBox8.Text;
cmd.Parameters.Add("#select", SqlDbType.Int).Value = 1;
cmd.Parameters.Add("#id");
cmd.ExecuteNonQuery();
Label1.Text = "Inserted Successfully";
con.Close();
bindGrid(GridView1);
}
ALTER procedure [dbo].[employeedtl](#select int,#empid int,#empname varchar(50),#empage int,#empaddress varchar(max),#empjoindate varchar(50),#empproject varchar(50),#empmobile bigint,#empemail varchar(max))
as
begin
if #select=1
begin
if Exists(select * from EmployeeDB where Empid=#empid)
begin
update EmployeeDB set [EmpId]=#empid,[EmpName]=#empname,[EmpAge]=#empage,[EmpAddress]=#empaddress,[EmpJoin]=#empjoindate,[EmpProj]=#empproject,[EmpMobile]=#empmobile,[EmpEmail]=#empemail where Empid=#empid
end
else
begin
insert into EmployeeDB(EmpId,EmpName,EmpAge,EmpJoin,EmpAddress,EmpProj,EmpMobile,EmpEmail) values(#empid,#empname,#empage,#empaddress,#empjoindate,#empproject,#empmobile,#empemail)
end
end
else if #select=2
begin
delete from EmployeeDB where EmpId=#empid
end
end
cmd.Parameters.Add("#id"); // remove this
Remove #id in ALTER PROCEDURE dbo.Employeetl
Remove id in insert INSERT INTO EmployeeDB(EmpName, . . . )
Need two changes
Pass value to #id parameter in code
cmd.Parameters.Add("#id", SqlDbType.Int).Value = xxx;
Alter stored procedure to update INSERT Command
INSERT INTO EMPTable(id,empname,empid,empage,empaddress,empjoindate,empproject,empm‌​obile,empemail,selec‌​t) values (#empname,#empid,#empage,#empaddress,#empjoindate,#empprojec‌​t,#empmobile,#empema‌​il,#select)
-------^
remove this ID column from INSERT with its value #id
Alter your stored procedure
// SQL Server stored procedure
alter storedprocedure employeedtl (
#id int = null,
#empname nvarchar(50) = null,
.
.
.
)
// in .Net remove this line
cmd.Parameters.Add("#id");

SQL Output Parameter

I have a questionnaire which stores answers for each user who does the test. I need to store the output in the database (which is the user doing the test.) I'm not quite sure what i am doing wrong. Currently my inputID returns 0. (InputAnswers inputs the test answers for that user to database)
CREATE PROCEDURE [dbo].[InputAnswers]
#QuestionID int,
#InputID int OUTPUT,
#Answer nchar,
#Remark nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Answers (InputID, QuestionID, Answer, Remark) VALUES (#InputID, #QuestionID, #Answer, #Remark)
END
The code below loads the answers from the list view which holds the questions:
private void LoadAnswers(int inputID)
{
foreach (StepControl step in dckSteps.Children)
{
foreach (QuestionControl quest in step.listQuestions.Items)
{
int questionID = quest.questionID;
string answer = quest.answer;
string remark = quest.txtRemark.Text;
SqlConnection conDatabase = new SqlConnection(String.Format(#"Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLSERVER_ID, SQLDatabaseName, SQLServerLoginName, SQLServerPassword));
string query = "InputAnswers";
SqlCommand cmd = new SqlCommand(query, conDatabase);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#InputID", SqlDbType.Int).Value = inputID;
cmd.Parameters.Add("#QuestionID", SqlDbType.Int).Value = questionID;
cmd.Parameters.Add("#Answer", SqlDbType.NChar).Value = answer;
cmd.Parameters.Add("#Remark", SqlDbType.NVarChar).Value = remark;
conDatabase.Open();
cmd.ExecuteNonQuery();
conDatabase.Close();
}
}
}
I then load these answers into the button click method:
private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
string name = txtName.Text;
string cno = txtCNO.Text;
var date = datePicker.SelectedDate;
int inputID = 0;
SqlConnection conDatabase = new SqlConnection(String.Format(#"Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLSERVER_ID, SQLDatabaseName, SQLServerLoginName, SQLServerPassword));
string query = "SaveInput";
SqlCommand cmd = new SqlCommand(query, conDatabase);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#InputID", SqlDbType.Int).Value = ParameterDirection.Output;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
cmd.Parameters.Add("#CNO", SqlDbType.NVarChar).Value = cno;
cmd.Parameters.Add("#Date", SqlDbType.DateTime).Value = date;
conDatabase.Open();
cmd.ExecuteNonQuery();
conDatabase.Close();
LoadAnswers(inputID);
}
This all works correctly apart from sending the OUTPUT back to the database. Any ideas?
EDIT: The procedure SaveInput looks like this: (SaveInput stores the user info)
CREATE PROCEDURE [dbo].[SaveInput]
#InputID int OUTPUT,
#Name nvarchar(50),
#CNO nvarchar(50),
#Date DATETIME
AS
BEGIN
SET NOCOUNT ON;
IF(#InputID = 0)
BEGIN
INSERT INTO Input (Name, CNO, Date) VALUES (#Name, #CNO, #Date)
SET #InputID = ##IDENTITY
END
ELSE
BEGIN
UPDATE Input SET Name = #Name,
CNO = #CNO,
Date = #Date
WHERE InputID = #InputID
END
END
I have a feeling i don't need to use OUTPUT on both procedures.
This is at least part of the problem:
cmd.Parameters.Add("#InputID", SqlDbType.Int).Value = ParameterDirection.Output;
That's creating an input parameter - but giving it a value which is the enum value ParameterDirection.Output. You want:
cmd.Parameters.Add("#InputID", SqlDbType.Int).Direction = ParameterDirection.Output;
You then need to fetch the result from the parameter after executing the command:
cmd.ExecuteNonQuery();
// You might want to store the parameter reference in a local variable instead
// of fetching it again afterwards.
int inputId = (int) cmd.Parameters["#InputID"].Value;
If you want the parameter to be input/output though, you should be using ParameterDirection.InputOutput (and giving it a value before executing the command). For example:
int inputId = ...;
var inputIdParameter = cmd.Parameters.Add("#InputID", SqlDbType.Int);
inputIdParameter.Direction = ParameterDirection.InputOutput;
inputIdParameter.Value = inputId;
...
cmd.ExecuteNonQuery();
inputId = (int) inputIdParameter.Value;

Categories