I have the following stored procedure written in SQL database. It executes 2 procedures in different databases. The inner procedures are simple update and insert queries without any explicit TRANSACTION statement applied.
ALTER PROCEDURE [dbo].[usp_1]
#UserID nvarchar(MAX),
#report nvarchar(max),
#sqlErrorMsg nvarchar(MAX) OUTPUT
AS
BEGIN
EXEC #ret = [db1].[dbo].[usp_2]
#user = #UserID,
#msg = #sqlErrorMsg OUTPUT,
#date = #reportDate
set #sqlErrorMsg = 'Report update Status: ' + #sqlErrorMsg
EXEC #ret = [db2].[dbo].[usp_3]
#UserID = #UserID,
#msg = #sqlErrorMsg OUTPUT,
#date = #reportDate
END
This procedure runs perfectly when I execute it in SQL Management studio. But when I run it using a C# code that calls this procedure, I get the following error:
The current transaction cannot be committed and cannot support
operations that write to the log file. Roll back the transaction. The
current transaction cannot be committed and cannot support operations
that write to the log file. Roll back the transaction.
C# Code: (Conn is defined outside with proper connection string and is tested)
public int Upload_Excel_Timer(string userID, string report, out string message)
{
int ret;
SqlCommand cmd = new SqlCommand("usp_1", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserID", userID);
cmd.Parameters.AddWithValue("#report", report);
SqlParameter outputParameter = cmd.Parameters.Add("#sqlErrorMsg", SqlDbType.NVarChar, 255);
outputParameter.Direction = ParameterDirection.Output;
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
try
{
if (conn.State.Equals(ConnectionState.Closed))
conn.Open();
int tempval = cmd.ExecuteNonQuery();
ret = Convert.ToInt32(returnParameter.Value);
message = outputParameter.Value.ToString();
}
catch (Exception e)
{
ret = -1;
message = e.Message;
}
finally
{
conn.Close();
}
return ret;
}
Related
I am trying to return a value from the code below but I am getting an error that says:
A SqlParameter with parameter name '#vRESULT' is not contained by this SqlParameterCollection
c# Code:
public int userLogin()
{
string connStr = ConfigurationManager.ConnectionStrings["conn"].ToString();
string cmdStr = #"fucn_LOg";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(cmdStr, conn))
{
try
{
conn.Open();
cmd.CommandText = cmdStr;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters[":vResult"].Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("param1", SqlDbType.VarChar)).Value = TB_1.Text;
cmd.Parameters.Add(new SqlParameter("param2", SqlDbType.VarChar)).Value = TB_2.Text;
cmd.ExecuteScalar();
return Int32.Parse(cmd.Parameters[":vResult"].Value.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return -1;
}
}
}
the sql server function code below with returning parameter DECLARE #vResult int
CREATE FUNCTION USER_LOGIN(#USER_NAME VARCHAR(60),
#PWD VARCHAR(60))
RETURNS INT
AS BEGIN
DECLARE #vResult int
SELECT #vRESULT=COUNT(*)
FROM OPER
WHERE UPPER(UNAM)=UPPER(#USER_NAME)
AND PSW=#PWD
IF #vResult=1
SET #vResult=1
ELSE
SET #vResult= -1
RETURN #vResult
END
Just Get result from Stroed Procedure like this:
var result = cmd.ExecuteScalar();
return Int32.Parse(result.ToString());
This gets first and Only result from Stored Procedure.
Also recommend simplify your code Like this:
public int userLogin() {
string connStr = ConfigurationManager.ConnectionStrings["conn"].ToString();
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand("fucn_LOg", conn)) {
try {
cmd.Connection.Open();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#param1", TB_1.Text);
cmd.Parameters.AddWithValue("#param2", TB_2.Text);
var result = cmd.ExecuteScalar();
return Int32.Parse(result.ToString());
}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
return -1;
}
finally {
if (cmd.Connection.State != ConnectionState.Closed) cmd.Connection.Close();
}
}
}
And your Stored procedure should looks Like this:
CREATE PROCEDURE fucn_LOg
(
#param1 nvarchar(max),
#param2 nvarchar(max)
)
AS
BEGIN
SET NOCOUNT ON;
if (exists(select * from tbUsers where flLogin = #param1 and flPassword = #param2))
begin
return 1;
end
else
begin
return 0;
end
END
GO
OR
CREATE PROCEDURE fucn_LOg
(
#param1 nvarchar(max),
#param2 nvarchar(max)
)
AS
BEGIN
SET NOCOUNT ON;
select COUNT(*) from tbUsers where flLogin = #param1 and flPassword = #param2
END
GO
Several problems.
First, you don't need the cmd.Parameters.Clear();, as you just establish a new cmd.
Second, use # for SQL Server parameters.
Third, a parameter named vResult is not set, so cmd.Parameters[":vResult"].Direction is invalid. You need to assign its type and value. Make sure your stored procedure has this parameter set with correct SQL data type.
Lastly, I guess you return the vResult in your stored procedure like select #vResult; so make it a new vResult = function(vResult). But no, it is not how SQL Server work. It won't change your input parameter even though you return your #vResult. While, ExecuteScaler does. So, simply get your result back by var result = cmd.ExecuteScalar();.
You are getting data from a stored procedure, not getting back the parameter you sent. That's the supposed correct way.
conn.Open();
cmd.CommandText = cmdStr;
cmd.CommandType = CommandType.StoredProcedure;
//Base on sql you provided, it is no need for this part.
/*
SqlParameter vResult = new SqlParameter();
vResult.ParameterName = "#vResult";
vResult.Direction = ParameterDirection.Output;
vResult.SqlDbType = System.Data.SqlDbType.???;
vResult.Value = ???;
cmd.Parameters.Add(vResult);
*/
cmd.Parameters.Add("#param1", SqlDbType.VarChar).Value = TB_1.Text;
cmd.Parameters.Add("#param2", SqlDbType.VarChar).Value = TB_2.Text;
var result = cmd.ExecuteScalar();
return Int32.Parse(result.ToString());
This is hard to debug without the SP, but a couple of things jump out.
First, you need to use the '#' character as a prefix for your parameter names, not a colon.
Second, you should define your output parameter like this:
SqlParameter outputParam = new SqlParameter("#vResult", SqlDbType.Int);
outputParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outputParam);
I created a FILETABLE on SQL Server 2014 with all the default options with a view for retrieving data and stored procedures for inserting and deleting files. Please note that non-transactional access is not enabled on the database because the files shouldn't be visible on the file system.
The problem is that when I retrieve a file from the table and write it to disk, it isn't identical to the original and can't be opened with the associated program.
Code for the view:
SELECT stream_id, file_stream, name, CAST(creation_time AS DateTime) AS DateCreated, CAST(last_write_time AS DateTime) AS DateUpdated FROM dbo.DocumentFiles
Code for the insert procedure:
create PROCEDURE [dbo].[sp_DocumentFiles_create]
-- Add the parameters for the stored procedure here
#name nvarchar(255),
#data varbinary(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #id uniqueidentifier;
set #id = NEWID();
insert into DocumentFiles (stream_id, file_stream, name) VALUES(#id, #data, #name);
select #id;
END
Code used for reading:
DocumentFile result = null;
SqlCommand comm = new SqlCommand("SELECT * from DocumentView where stream_id = #id", conn);
comm.Parameters.Add(new SqlParameter("#id", id));
try
{
conn.Open();
SqlDataReader reader = comm.ExecuteReader();
while (reader.Read())
{
result = new DocumentFile();
result.stream_id = (Guid)reader["stream_id"];
result.file_stream = (byte[])reader["file_stream"];
result.name = reader["name"].ToString();
result.DateCreated = Convert.ToDateTime(reader["DateCreated"]);
result.DateUpdated = Convert.ToDateTime(reader["DateUpdated"]);
}
}
catch
{
}
finally
{
conn.Close();
}
return result;
Code used for inserting:
public Guid? Insert(DocumentFile obj)
{
Guid? result = null;
SqlCommand comm = new SqlCommand("sp_DocumentFiles_create", conn);
comm.CommandType = System.Data.CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter("#name", obj.name));
comm.Parameters.Add(new SqlParameter("#data", obj.file_stream));
try
{
conn.Open();
result = comm.ExecuteScalar() as Guid?;
}
finally
{
conn.Close();
}
return result;
}
The only files that I managed to insert and retrieve intact are image files. I tried using various ms office documents (.doc, .docx, .pptx, etc) as well as archives (rar, zip).
I have a problem while inserting records into SQL Server.
The string from C# doesn't show up in SQL Server as I'm inserting the sql just insert the first char
Example: If I insert 22222 in the data base just the first 2 inserted
Note I'm using a stored procedure for my first time.
This is my code:
public void insert_workshop(DateTime Pdate, string PTime, string PDesc, byte[] Img)
{
SqlCommand cmd = new SqlCommand("[InsertWorkShops]", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#WorkshopsDate", SqlDbType.Date).Value = Pdate;
cmd.Parameters.Add("#Time", SqlDbType.NVarChar).Value = PTime;
cmd.Parameters.Add("#WorkshopsDescription", SqlDbType.NVarChar).Value = PDesc;
cmd.Parameters.Add("#WorkshopsImage", SqlDbType.Image).Value = Img;
cmd.Parameters.Add("#CreatedBy", SqlDbType.NVarChar).Value = 1;
try
{
cmd.ExecuteNonQuery();
Msg = "Add Done ";
}
catch
{
Msg = "Error While Adding";
}
WorkShopTransactions Ws = new WorkShopTransactions();
Ws.insert_workshop(WorkShopDT.Value, txtWorshopTime.Text.ToString(),
txtWorkshopDescriptions.Text.ToString(), img);
T-SQL:
ALTER PROCEDURE [dbo].[InsertWorkShops]
#WorkshopsDate date,
#Time nvarchar,
#WorkshopsDescription nvarchar,
#WorkshopsImage image,
#CreatedBy int
AS
BEGIN
SET NOCOUNT ON;
insert into Workshops
values(#WorkshopsDate, #Time, #WorkshopsDescription, #WorkshopsImage, #CreatedBy)
END
In the stored procedure, you have declared your nvarchar parameters without a length. They default to nvarchar(1).
i have that code using LINQ to call a stored procedure to save some data into database then return two variables from the stored procedure.
[ASP.NET code]
dbDataContext dbo = new dbDataContext();
dbo.AddNewDoctor(doctorName, email, password, ref DocId, ref result);
[SQL]
create PROCEDURE [dbo].[AddNewDoctor]
#doctorname nvarchar(100),
#email nvarchar(100),
#password nvarchar(MAX),
#docId int out,
#Result int out
AS
BEGIN
SET NOCOUNT ON;
declare #idCounter int
select #idCounter = count(*) from dbo.doctors
if EXISTS (select * from dbo.doctors where e_mail = #email)
begin
SET #Result = -1
set #docId= 0
end
else
begin
INSERT INTO [dbo].[doctors]
([doctor_id]
,[doctorname]
,[e_mail]
,[password]
VALUES
((#idCounter +1)
,#docotorname
,#email
,#password
)
SET #Result = 1
set #docId= (#idCounter + 1)
end
END
this code work very well what i want to do now to use ADO instead of LINQ, the problem with me is that i can't pass the ref variable as in LINQ so how can i do it using ADO
You'll have to do something like this. Use ParameterDirection
SqlParameter output = new SqlParameter(paramName, dbType);
output.Direction = ParameterDirection.Output;
command.Parameters.Add(output);
In your case you've to use SqlDbType.Int. Use Value property to read return value.
SqlParameter output = new SqlParameter(paramName, SqlDbType.Int);
output.Direction = ParameterDirection.Output;
command.Parameters.Add(output);
int Result = (int) output.Value; or int? Result = (int?) output.Value;
Try this
using (SqlConnection con = new SqlConnection("Your connection string"))
{
con.Open();
SqlCommand mycommand = new SqlCommand();
mycommand.Connection = con;
mycommand.CommandText = "dbo.AddNewDoctor";
mycommand.CommandType = CommandType.StoredProcedure;
mycommand.Parameters.AddWithValue(doctorName);
mycommand.Parameters.AddWithValue(email);
mycommand.Parameters.AddWithValue(password);
mycommand.Parameters.AddWithValue(ref DocId);
mycommand.Parameters.AddWithValue(ref result);
mycommand.ExecuteNonQuery();
}
Hope this helps thanks.
Refer to this article, there is an working example:
http://csharp-guide.blogspot.de/2012/05/linq-to-sql-call-stored-procedure-with_25.html
I m creating new user registration moduleand for that i wrote following stored proc.
PROCEDURE [dbo].[addNewUser]
-- Add the parameters for the stored procedure here
#usertype VarChar(10),
#useremail VarChar(70),
#userpass VarChar(20),
#fullname VarChar(70),
#city VarChar(70),
#state Int,
#allowAlerts Bit,
#allowLetter Bit,
#aboutMe NVARCHAR(160)
As
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if ((select count(user_info._id) from user_info where useremail like #useremail) = 0)
BEGIN
Insert Into user_info
(usertype,useremail,userpass,fullname,city,[state],allowAlerts,allowLetters,aboutMe)
Values
(
#usertype,
#useremail,
#userpass ,
#fullname,
#city,
#state,
#allowAlerts,
#allowLetter,
#aboutMe
)
Select ##IDENTITY as NewID
END
Else
BEGIN
Print '-1'
END
And following is the simple ASP.net C# Code that I try to use
public int registerNewUser(string usertype, string useremail, string userpass, string fullname, string city, string state, string allowAlerts, string allowLetter, string aboutMe)
{
con = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "addBlogEntry";
cmd.Parameters.Add("#usertype", SqlDbType.VarChar).Value = usertype;
cmd.Parameters.Add("#useremail", SqlDbType.VarChar).Value = useremail;
cmd.Parameters.Add("#userpass", SqlDbType.VarChar).Value = userpass;
cmd.Parameters.Add("#fullname", SqlDbType.VarChar).Value = fullname;
cmd.Parameters.Add("#city", SqlDbType.VarChar).Value = city;
cmd.Parameters.Add("#state", SqlDbType.VarChar).Value = Convert.ToInt16(state);
cmd.Parameters.Add("#allowAlerts", SqlDbType.VarChar).Value = Convert.ToInt16(allowAlerts);
cmd.Parameters.Add("#allowLetter", SqlDbType.VarChar).Value = Convert.ToInt16(allowLetter);
cmd.Parameters.Add("#aboutMe", SqlDbType.VarChar).Value = aboutMe;
try
{
if (con.State != ConnectionState.Open)
con.Open();
cmd.ExecuteNonQuery();
con.Close();
con.Dispose();
// some code to be written here so that i can return userID(success) or -1(if that username is already registered)
return 0;
}
catch (Exception Ex)
{
con.Close();
con.Dispose();
return 0;
}
}
Through my C# code i want to return either auto generated userId which my stored procedures returns to me or if user alrady exists than i want to return -1
Please tell how to do this?
Thanks in advance :)
Yes, you can use ExecuteScalar() and change
Print '-1'
into
Select -1 as NewID
First of all, you should use SELECT SCOPE_IDENTITY() inside your stored proc to retrieve the new ID value (##IDENTITY can return false results).
And yes, if you want to get the result back, you need to call either .ExecuteScalar() or .ExecuteReader() and then read that value back.
And while you're at it - I'd also recommend putting your SqlConnection and SqlCommand objects into using blocks - so instead of your code, use this:
using(con = new SqlConnection(connectionString))
using(cmd = new SqlCommand(con))
{
..... // put the rest of your code here
}
If you want to create an output parameter for your stored proc, and set it to the new key you can access it that way. ExecuteNonQuery will return the number of rows affected, so that can be used as well. Something like this:
cmd.Parameters.Add("#uniquID", SqlDbType.Int).Direction = ParameterDirection.Output;
// Your other code...
var result = cmd.ExecuteNonQuery();
// Your other code...
return (result == 1) ? (int)cmd.Parameters["#uniquID"].Value : -1;