ADO.NET - Trouble Getting Output Parameter - sql-server

My DBA created the following Stored Proc which he insists works fine when called in SQL Server:
CREATE procedure [dbo].[GetParentID]
#SSHIP_AppID as varchar(50),
#ParentID as varchar(150) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #ParentID = a.iBuild_GUID
FROM dbo.XRef_iBuild_SSHIP as a
WHERE a.SSHIP_appId = #SSHIP_AppID
AND a.SSHIP_appId <> ''
END
I have created the following ADO.NET Wrapper but I am having trouble getting the output parameter. I keep getting back "OUTPUT" as its value:
private string GetParentId(string appId)
{
var connection = new SqlConnection();
string parentId = String.Empty;
try
{
connection.ConnectionString = "...)
var command = new SqlCommand("GetParentId", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#SSHIP_AppID", appId));
command.Parameters.Add(new SqlParameter("#ParentID", ParameterDirection.Output));
connection.Open();
command.ExecuteNonQuery();
parentId = (command.Parameters["#ParentId"].Value).ToString();
}
catch (Exception ex)
{
LogError(appId, ex.ToString(), "Interface12 - Cannot get ParentId", null, 0);
}
finally
{
connection.Close();
}
return parentId;
}
}
What am I doing wrong?

In new SqlParameter("#ParentID", ParameterDirection.Output) the 2nd argument is treated as the object value argument and apparently converted to a string.
(This implicit conversion is, in my opinion, a design flaw in ADO.NET. It should throw an exception for any unknown input type.).
Choose a better overload.

Related

Getting String Value From Database in C#

I have a database table in which i am saving created users along with username now what i want to get string value from my database if username exists in database and then i will show error message "UserName Exists or Choose new one etc etc"
here is my stored procedure
ALTER PROCEDURE [dbo].[p_SaveUpdate_AdminUserAccount]
(
#Id_User int,
#nm_UserName varchar(50),
#nm_UserPassword varchar(50),
#nm_UserRole int
)
AS
BEGIN
IF #Id_User=0
BEGIN
Declare #count int
Select #count=COUNT(1) from ref_Admin_UserAccount where nm_UserName=#nm_UserName
if(#count > 0)
begin
select -1 as a;
end
else
BEGIN
SET NOCOUNT ON;
Insert into ref_Admin_UserAccount(nm_UserName,nm_UserPassword,nm_UserRole)
values(#nm_UserName,#nm_UserPassword,#nm_UserRole)
SELECT SCOPE_IDENTITY();
end
END
ELSE
BEGIN
SET NOCOUNT ON;
UPDATE ref_Admin_UserAccount
SET
nm_UserName=#nm_UserName,
nm_UserPassword=#nm_UserPassword,
nm_UserRole=#nm_UserRole
WHERE Id_User=#Id_User;
SELECT #Id_User;
End
End
and here is my code to save values in database from presentation layer using 3 tier archiecture
public int SaveAdminUserAccountInformation(AdminAccountProperties oAdminUser)
{
try
{
SqlParameter[] parm = new SqlParameter[4];
parm[0] = new SqlParameter(PARM_ADMIN_USER_ID, SqlDbType.Int);
parm[0].Value = oAdminUser.UserID;
parm[1] = new SqlParameter(PARM_USER_NAME, SqlDbType.VarChar);
parm[1].Value = oAdminUser.UserName;
parm[2] = new SqlParameter(PARM_ADMIN_USER_PASSWORD, SqlDbType.VarChar);
parm[2].Value = oAdminUser.Password;
parm[3] = new SqlParameter(PARM_USER_ROLE, SqlDbType.Int);
parm[3].Value = oAdminUser.UserRole;
return Convert.ToInt32(SqlHelper.ExecuteScalar(this._ConnString, CommandType.StoredProcedure, SQL_ADMIN_USER_INSERT_UPDATE, parm));
}
catch (Exception ex)
{
throw ex;
}
}
please give me some help.
Your stored procedure returns -1 if username exists so i suggest you to return int rather than string in your Data Access Layer.
here is some modifications in your code
public int SaveAdminUserAccountInformation(AdminAccountProperties oAdminUser)
{
try
{
SqlParameter[] parm = new SqlParameter[4];
parm[0] = new SqlParameter(PARM_ADMIN_USER_ID, SqlDbType.Int);
parm[0].Value = oAdminUser.UserID;
parm[1] = new SqlParameter(PARM_USER_NAME, SqlDbType.VarChar);
parm[1].Value = oAdminUser.UserName;
parm[2] = new SqlParameter(PARM_ADMIN_USER_PASSWORD, SqlDbType.VarChar);
parm[2].Value = oAdminUser.Password;
parm[3] = new SqlParameter(PARM_USER_ROLE, SqlDbType.Int);
parm[3].Value = oAdminUser.UserRole;
int a =Convert.ToInt32(SqlHelper.ExecuteScalar(this._ConnString, CommandType.StoredProcedure, SQL_ADMIN_USER_INSERT_UPDATE, parm));
return a;
}
catch (Exception ex)
{
throw ex;
}
}
after this on basis of return value do what ever you want to do in presentation layer.
Instead Selecting the New row in Stored Procedure. Use an OUT Parameter of the Stored Procedure. Like the Code Below :
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "USP_IUD_FAC_SUBJECT";
cmd.Parameters.AddWithValue("#EVENT", EVENTI);
cmd.Parameters.AddWithValue("#FAC_SUB_CODE", FAC_SUB_CODE);
cmd.Parameters.AddWithValue("#FAC_SUB_NAME", FAC_SUB_NAME);
cmd.Parameters.AddWithValue("#TRAN_DATE", TRAN_DATE);
cmd.Parameters.AddWithValue("#TRAN_USER_ID", TRAN_USER_ID);
cmd.Parameters.AddWithValue("#APPROVED", APPROVED);
cmd.Parameters.AddWithValue("#APPROVED_DATE", APPROVED_DATE);
cmd.Parameters.AddWithValue("#APPROVED_USER_ID", APPROVED_USER_ID);
SqlParameter outparameter = new SqlParameter("#MSG", SqlDbType.NVarChar, 200);
outparameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outparameter);
SqlParameter OutId = new SqlParameter("#RETURNOUTID", SqlDbType.Int);
OutId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(OutId);
cmd.ExecuteNonQuery();
object msg = cmd.Parameters[outparameter.ParameterName].Value;
ReturnId2 = Convert.ToString(cmd.Parameters[OutId.ParameterName].Value);
return Convert.ToString(msg);
}
catch (Exception ex)
{
transaction.Rollback();
throw new ArgumentException(ex.Message);
}
finally
{
transaction.Commit();
DL_CCommon.Connection().Close();
}
So, Create the Stored Procedure with an Out Parameter. And, Set the Required value into that Out parameter in Procedure. For using Out Parameter in Stored Procedure Follow the link : http://www.codeproject.com/Articles/126898/Sql-Server-How-to-write-a-Stored-procedure-in-Sql
SQL
ALTER PROCEDURE [dbo].[p_SaveUpdate_AdminUserAccount]
#Id_User int,
#nm_UserName varchar(50),
#nm_UserPassword varchar(50),
#nm_UserRole int,
#id int OUTPUT
AS
C#
SqlConnection db = DataConn.SqlConnection();
SqlCommand sqlComm = new SqlCommand(
"p_SaveUpdate_AdminUserAccount #Id_User, #nm_UserName, #nm_UserPassword, #nm_UserRole, #id", db, transaction) { CommandType = CommandType.Text };
sqlComm.Parameters.Add(new SqlParameter("#Id_User", SqlDbType.Int)).Value;
sqlComm.Parameters.Add(new SqlParameter("#nm_UserName", SqlDbType.VarChar)).Value;
sqlComm.Parameters.Add(new SqlParameter("#nm_UserPassword", SqlDbType.VarChar)).Value;
sqlComm.Parameters.Add(new SqlParameter("#nm_UserRole", SqlDbType.VarChar)).Value;
sqlComm.Parameters.Add(new SqlParameter("#id", SqlDbType.Int) { Direction = ParameterDirection.Output });
sqlComm.Parameters.Add(param);
sqlComm.ExecuteNonQuery();

String concatenation problems in SQL Server

ALTER PROCEDURE [dbo].[InsertSMS]
-- Add the parameters for the stored procedure here
#SmsMsgDesc Nvarchar(Max)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [Tbl_Log]([LogDescription])VALUES (#SmsMsgDesc)
declare #LogID int;
SET #LogID = CAST(SCOPE_IDENTITY() AS INT)
INSERT INTO [Tbl_SMS]
([SmsMsgDesc])
VALUES
**(#SmsMsgDesc+CAST(#LogID AS NVarchar(12)))**
END
Problem here is sometimes concatenation does not concatenate the last string I don't know why
Even if I do it like this
INSERT INTO [Tbl_SMS]
([SmsMsgDesc])
VALUES
**(#SmsMsgDesc+'Test')**
the constant 'Test' sometimes doesn't appear at the end of the string this drives me crazy please help !
i'm calling this procedure using the following C# function :-
public int InsertSMSDB(string Message)
{
try
{
//int LogID;
SqlConnection Conn=new SqlConnection(SmsDBConnection);
SqlCommand Comm = new SqlCommand("InsertSMS", Conn);
Comm.CommandType = System.Data.CommandType.StoredProcedure;
Comm.Parameters.AddWithValue("#SmsMsgDesc", Message);
Conn.Open();
int RowEffected=Comm.ExecuteNonQuery();
Conn.Close();
if (RowEffected > 0)
{
return RowEffected;
}
else
{
return -1;
}
}
catch (SqlException ex)
{
return -1;
}
}
Finally Some information may help in investegating this case in the Application there is 2 threads access the Tbl_SMS one Thread for Insertion and 1 Thread for Selection
If the value passed to procedure #SmsMsgDesc is null then it will not concatenate
try this to avoid the null value
VALUES
(isnull(#SmsMsgDesc,'')+CAST(#LogID AS NVarchar(12)))
Alternatively
you could change the procedure header
ALTER PROCEDURE [dbo].[InsertSMS]
#SmsMsgDesc Nvarchar(Max)=''

Getting a result feedback from a stored procedure in Entity Framework

In a SQL Server 2008 I have a simple stored procedure moving a bunch of records to another table:
CREATE PROCEDURE [dbo].MyProc(#ParamRecDateTime [datetime])
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].Table2
SELECT
...,
...
FROM [dbo].Table1
WHERE RecDateTime <= #ParamRecDateTime
DELETE FROM [dbo].Table1
WHERE RecDateTime <= #ParamRecDateTime
END
Running it from within SQL Server Management Studio, I get the job done and return value = 0
DECLARE #return_value int
EXEC #return_value = dbo.MyProc #ParamRecDateTime = '2011-06-25 11:00:00.000'
SELECT 'Return Value' = #return_value
But when I call the same stored procedure from an app using Entity framework, I also get the job done but the return value is "-1":
int result = myrepository.MyProc(datetimePar);
MessageBox.Show(result.ToString());
I didn't manage to find an explanation for this error, but found this discouraging post, where it's said that there is no standard for this type of return codes in SQL Server.
What is the good, reliable way of getting know of a Stored Procedure execution result when calling it from Entity Framework and when the Stored Procedure doesn't return any entities?
One way to do it is to call ExecuteStoreCommand, and pass in a SqlParameter with a direction of Output:
var dtparm = new SqlParameter("#dtparm", DateTime.Now);
var retval = new SqlParameter("#retval", SqlDbType.Int);
retval.Direction = ParameterDirection.Output;
context.ExecuteStoreCommand("exec #retval = MyProc #dtparm", retval, dtparm);
int return_value = (int)retval.Value;
Originally I tried using a direction of ReturnValue:
retval.Direction = ParameterDirection.ReturnValue;
context.ExecuteStoreCommand("MyProc #dtparm", retval, dtparm);
but retval.Value would always be 0. I realized that retval was the result of executing the MyProc #dtparm statement, so I changed it to capture the return value of MyProc and return that as an output parameter.
using (dbContext db = new dbContext())
{
var parameters = new[]
{
new SqlParameter("#1","Input Para value"),
new SqlParameter("#2",SqlDbType.VarChar,4){ Value = "default if you want"},
new SqlParameter("#3",SqlDbType.Int){Value = 0},
new SqlParameter("#4","Input Para Value"),
new SqlParameter("#5",SqlDbType.VarChar,10 ) { Direction = ParameterDirection.Output },
new SqlParameter("#6",SqlDbType.VarChar,1000) { Direction = ParameterDirection.Output }
};
db.ExecuteStoreCommand("EXEC SP_Name #1,#2,#3,#4,#5 OUT,#6 OUT", parameters);
ArrayList ObjList = new ArrayList();
ObjList.Add(parameters[1].Value);
ObjList.Add(parameters[2].Value);
}
See OUTPUT attribute for SQL param of store procedure,
here
For future reference: I had the same issue but needed multiple OUTPUT variables. The solution was a combination of both answers. Below is a complete sample.
public void MyStoredProc(int inputValue, out decimal outputValue1, out decimal outputValue2)
{
var parameters = new[] {
new SqlParameter("#0", inputValue),
new SqlParameter("#1", SqlDbType.Decimal) { Direction = ParameterDirection.Output },
new SqlParameter("#2", SqlDbType.Decimal) { Direction = ParameterDirection.Output }
};
context.ExecuteStoreCommand("exec MyStoredProc #InParamName=#0, #OutParamName1=#1 output, #OutParamName2=#2 output", parameters);
outputValue1 = (decimal)parameters[1].Value;
outputValue2 = (decimal)parameters[2].Value;
}
Please note the Types used (decimal.) If another type is needed, remember to not only change it in the method argument list but also the SqlDbType.XXX.

How to save byte[] using a procedure?

This stored procedure does not save the data, it seems to be a problem with the VARBINARY. I am passing a byte[] to it, but then it doesn't work. If I send this parameter as NULL it works.
I'm calling the procedure with the following code:
public Community AddCommunity(string name, string description, byte[] picture, User owner, int? venue, int communityID)
{
using (var database = new Database())
{
return database.Scope.GetSqlQuery<Community>("QP_AddCommunity ?, ?, ?, ?, ?, ?", "VARCHAR Name, VARCHAR Description, VARBINARY Picture, INTEGER Owner, INTEGER Venue, INTEGER ID").GetResult(name, description, picture, owner.ID, venue, communityID);
}
}
The procedure is the following:
CREATE PROCEDURE [dbo].[QP_AddCommunity]
#Name VARCHAR(120),
#Description VARCHAR(MAX),
#Picture VARBINARY(MAX),
#Owner INTEGER,
#Venue INTEGER,
#ID INTEGER
AS
BEGIN
SET NOCOUNT ON;
IF(SELECT COUNT(*) FROM QT_Community WHERE ID = #ID) = 0
INSERT INTO QT_Community(Name, [Description], Picture, [Owner], Venue) VALUES(#Name, #Description, #Picture, #Owner, #Venue);
ELSE
UPDATE QT_Community SET Name = #Name, [Description] = #Description, Picture = #Picture, [Owner] = #Owner, Venue = #Venue WHERE ID = #ID;
SELECT * FROM QT_Community WHERE ID = ##IDENTITY;
END
What's wrong with this code? Isn't VARBINARY a byte[] ?
This code works when executing on SQL Server Management Studio.
DECLARE #X varbinary(20)
Set #X = CAST('Testing' As varbinary(20))
EXECUTE [QP_AddCommunity] 'aaaaa', 'descricao', #X, 216, NULL, 0;
But when calling from the GetSqlQuery method with something on the byte[] the transaction says it's not active and not dirty. BUT if the byte[] is null it works as it should.
i found that it is impossible as this answer shows
Hello gaurav, currently our
GetSqlQuery method cannot operate
properly with parameters of type
LongVarBinary or VarBinary, thus
making it impossible for the stored
procedure to work as expected. We are
aware of this problem and we are
working on fixing it. As a work around
you should try and use Linq to achieve
your goal. Greetings, Petar the
Telerik team
Accordingly to this table it seems either BLOB, BINARY, VARBINARY would be valid types for [] of primitive type.
You could try to ask on their forums, maybe someone will be able to help you.
Try using the .WRITE method. On your INSERT, insert 0x for Picture, then update independently.
UPDATE QT_Community
SET Picture.Write (#Picture, 0, DATALENGTH(Picture))
WHERE ID = #ID
Example (Ado.Net):
byte[] ba = UlongsToBytes(ul);
try
{
string source = #"packet size=4096;integrated security=SSPI;data source=MyPC\MyNamedInstance;persist security info=False;initial catalog=Sandbox";
SqlConnection conn = new SqlConnection(source);
conn.Open();
SqlCommand a = new SqlCommand("INSERT BigintsTarget(bi) SELECT * FROM dbo.ParseImageIntoBIGINTs(#BIGINTs)", conn);
a.CommandType = System.Data.CommandType.Text;
a.Parameters.Add(new SqlParameter("#BIGINTs", System.Data.SqlDbType.Image,2147483647));
for(int q=0; q<10; q++)
{
a.Parameters[0].Value = ba;
int res = a.ExecuteNonQuery();
}
d2 = DateTime.Now;
SqlCommand b = new SqlCommand("INSERT BigintsTarget1(bi) SELECT * FROM dbo.ParseVarcharMAXIntoBIGINTs(#BIGINTs)", conn);
b.CommandType = System.Data.CommandType.Text;
b.Parameters.Add(new SqlParameter("#BIGINTs", System.Data.SqlDbType.VarChar,2147483647));
for(int q=0; q<10; q++)
{
b.Parameters[0].Value = sss;
int res = b.ExecuteNonQuery();
}
//b.ExecuteNonQuery();
conn.Close();
}
catch(Exception ex)
{
string s = ex.Message;
int t=0;
t++;
}
}

Incorrect syntax near stored procedure error

I'm updating a long list of records. In my code, everything run as predicted until it execute the query. I get an
Incorrect syntax near 'TempUpdatePhysicalCityStateZip'
(my stored procedure name). I've tested it with SQL Server Management Studio and it runs fine. So, I'm not quite sure where I got it wrong. Below is my stored procedure and code:
ALTER PROCEDURE [dbo].[TempUpdateCityStateZip]
#StoreNo nvarchar (11),
#City nvarchar(50),
#State nvarchar(2),
#Zip nvarchar(5)
AS
BEGIN
SET NOCOUNT ON;
UPDATE StoreContact
SET City = #City, State = #State, Zip = #Zip
WHERE StoreNo = #StoreNo
END
Here is my code:
Dictionary<string, string> CityStateZipList = getCityStateZipList(dbPath);
using (SqlConnection conn = new SqlConnection(dbPath))
{
conn.Open();
SqlCommand cmdUpdate = new SqlCommand("TempUpdateCityStateZip", conn);
foreach (KeyValuePair<string, string> frKeyValue in CityStateZipList)
{
cmdUpdate.Parameters.Clear();
string[] strCityStateZip = frKeyValue.Value.Split(' ');
cmdUpdate.Parameters.AddWithValue("StoreNo", frKeyValue.Key.ToString());
foreach (String i in strCityStateZip)
{
double zipCode;
if (i.Length == 2)
{
cmdUpdate.Parameters.AddWithValue("State", i);
}
else if (i.Length == 5 && double.TryParse(i, out zipCode))
{
cmdUpdate.Parameters.AddWithValue("Zip", i);
}
else
{
cmdUpdate.Parameters.AddWithValue("City", i);
}
}
cmdUpdate.ExecuteNonQuery();
}
}
I believe you can get that puzzling error message if you don't specify the command type:
cmdUpdate.CommandType = CommandType.StoredProcedure;
Don't you need the # sign before the parameter?
cmdUpdate.Parameters.AddWithValue("#State", i);
FWIW, Thats kind of a dirty piece of code there, you will probably have many issues trying to maintain that. For performance reasons you may want to parse out the CityStateZipList before you open the connection, that way you aren't keeping it open longer than you need.

Resources