Stored Procedures with Mysql connector - c#

I'm trying to call a simple stored procedure in c# 2010.
With only a IN argument it's ok, but now with a OUT argument it's not working.
In phpmyadmin :
drop procedure if exists insert_artist;
delimiter $$
create procedure insert_student(IN name VARCHAR(100), OUT id INT)
begin
insert into student(name) values(name);
set id = last_insert_id();
end$$
delimiter ;
Then using
call insert_student("toto",#id);
select #id;
It's working fine.
Now, in c# :
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
using (MySqlCommand command = connection.CreateCommand())
{
command.CommandText = "insert_student";
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#name", "xxxx");
command.Parameters.AddWithValue("#id",MySqlDbType.Int32);
command.ExecuteNonQuery();
Console.WriteLine("**** " + command.Parameters["#id"].Value);
}
}
Gives me an exception when executing ExecuteNonQuery() :
OUT or INOUT argument 2 for routine insert_student is not a variable or NEW pseudo-variable in BEFORE trigger
The same thing without the out argument in the stored procedure is working fine.
Where is my mistake?

A fuller example:
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(nameOfStoredRoutine, connection);
cmd.CommandType = CommandType.StoredProcedure;
//input parameters
for (int i = 0; i < (parameterValue.Length / 2); i++)
{
cmd.Parameters.AddWithValue(parameterValue[i, 0], parameterValue[i, 1]);
cmd.Parameters[parameterValue[i, 0]].Direction = ParameterDirection.Input;
parameterList = parameterList + parameterValue[i,0] + " " + parameterValue[i,1] + " ";
}
//single output parameter
cmd.Parameters.AddWithValue("#output", MySqlDbType.Int32);
cmd.Parameters["#output"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery(); //Execute command
this.CloseConnection(); //close connection
return Convert.ToInt32(cmd.Parameters["#output"].Value.ToString());

my below code works
pls check if it's ok for you.
InsertQuery = New MySqlCommand("xxxxxx")
InsertQuery.Connection = Connection
InsertQuery.CommandType = Data.CommandType.StoredProcedure
InsertQuery.Parameters.AddWithValue("IN_xxx", str_xxxx)
InsertQuery.Parameters.Add("OUT_LastID", MySqlDbType.Int32).Direction = ParameterDirection.Output
IQ = InsertQuery.ExecuteReader()
IQ.Read()
LASTID = InsertQuery.Parameters("OUT_LastID").Value

Related

C# how to call an as 400 stored procedure using oledb

Hi I am trying to call an as400 stored procedure using OleDB. Could you please post an example of how to do it cause I've been following some tutorials but not matter what I do I always get an Invalid Token Exception
this is what I do
OleDbCommand sp = new OleDbCommand("CALL NASVARWG.SP001(?,?,?,?,?) ", connectionDB);
sp.CommandType = CommandType.StoredProcedure;
sp.Parameters.Add("P1", System.Data.OleDb.OleDbType.Char).Value = "ESANASTRIS";
sp.Parameters["P1"].Size = 10;
sp.Parameters["P1"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P2", System.Data.OleDb.OleDbType.Char).Value = "SAMNAS";
sp.Parameters["P2"].Size = 10;
sp.Parameters["P2"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P3", System.Data.OleDb.OleDbType.Char).Value = textBox_Reparto.Text;
sp.Parameters["P3"].Size = 6;
sp.Parameters["P3"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P4", System.Data.OleDb.OleDbType.Char).Value = "we can do this";
sp.Parameters["P4"].Size = 60;
sp.Parameters["P4"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P5", System.Data.OleDb.OleDbType.Char).Value = "help";
sp.Parameters["P5"].Size = 256;
sp.Parameters["P5"].Direction = ParameterDirection.Input;
sp.Prepare();
sp.ExecuteNonQuery();
the exception I get says "NASVARWG" is not a valid token. Why? that is the name of the library containing the procedure and the spelling is correct.
Thanks for your help
A C# code with CommandType.StoredProcedure example :
// assume a DB2Connection conn
DB2Transaction trans = conn.BeginTransaction();
DB2Command cmd = conn.CreateCommand();
String procName = "INOUT_PARAM";
cmd.Transaction = trans;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = procName;
A C# code with CommandType.Text example :
// assume a DB2Connection conn
DB2Transaction trans = conn.BeginTransaction();
DB2Command cmd = conn.CreateCommand();
String procName = "INOUT_PARAM";
String procCall = "CALL INOUT_PARAM (#param1, #param2, #param3)";
cmd.Transaction = trans;
cmd.CommandType = CommandType.Text;
cmd.CommandText = procCall;
// Register input-output and output parameters for the DB2Command
cmd.Parameters.Add( new DB2Parameter("#param1", "Value1");
cmd.Parameters.Add( new DB2Parameter("#param2", "Value2");
DB2Parameter param3 = new DB2Parameter("#param3", IfxType.Integer);
param3.Direction = ParameterDirection.Output;
cmd.Parameters.Add( param3 );
// Call the stored procedure
Console.WriteLine(" Call stored procedure named " + procName);
cmd.ExecuteNonQuery();
// Register input-output and output parameters for the DB2Command
...
// Call the stored procedure
Console.WriteLine(" Call stored procedure named " + procName);
cmd.ExecuteNonQuery();

SQL query with c# stringbuilder error near "=" symbol

I'm working on some code that creates procedures with C#. When I try to run my code:
StringBuilder sbSP1 = new StringBuilder();
sbSP1.AppendLine("CREATE PROCEDURE " + ProcN + "DELETE #id int=0 AS BEGIN DELETE FROM " + tname + " WHERE " + PK + " = #id END");
SqlConnection connection = new SqlConnection(connectionString);
using (SqlCommand cmd = new SqlCommand(sbSP1.ToString(), connection))
{
connection.Open();
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
connection.Close();
}
This part doesn't work. It throws an exception:
System.Data.SqlClient.SqlException: 'Incorrect syntax near '='.'
But when I try to run this part:
StringBuilder sbSP3 = new StringBuilder();
sbSP3.AppendLine("CREATE PROCEDURE " + ProcN + "GET AS BEGIN SET NOCOUNT ON; SELECT " + columns + " from " + tname + " END");
SqlConnection connection = new SqlConnection(connectionString);
using (SqlCommand cmd = new SqlCommand(sbSP3.ToString(), connection))
{
connection.Open();
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
connection.Close();
}
it runs correctly.
Where is my mistake in the first snippet of code?
Without sbSP1 final text it's difficult to pin down the error; as a working hypothesis I suggest that PK being complex (e.g. "id value")
should be escaped - [PK]. In order to avoid such kind of errors, please, never build the query, but make procedure's text being readable with a help of string interpolation - $ and verbatim strings - #.
//TODO: check the text, is it the procedure you want to create?
string text =
$#"create procedure [{ProcN}Delete]
#id int = 0 as
begin
delete
from [{tname}]
where [{PK}] = #id
end;";
//DONE: do not close connection manually, but wrap it into using
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
using (qlCommand cmd = new SqlCommand(text, connection)) {
cmd.ExecuteNonQuery();
}
}

How do I execute a SqlDataReader after sqlInsertCmd.ExecuteNonQuery

I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}

Calling stored procedure with return value

I am trying to call a stored procedure from my C# windows application. The stored procedure is running on a local instance of SQL Server 2008. I am able to call the stored procedure but I am not able to retrieve the value back from the stored procedure. This stored procedure is supposed to return the next number in the sequence. I have done research online and all the sites I've seen have pointed to this solution working.
Stored procedure code:
ALTER procedure [dbo].[usp_GetNewSeqVal]
#SeqName nvarchar(255)
as
begin
declare #NewSeqVal int
set NOCOUNT ON
update AllSequences
set #NewSeqVal = CurrVal = CurrVal+Incr
where SeqName = #SeqName
if ##rowcount = 0 begin
print 'Sequence does not exist'
return
end
return #NewSeqVal
end
Code calling the stored procedure:
SqlConnection conn = new SqlConnection(getConnectionString());
conn.Open();
SqlCommand cmd = new SqlCommand(parameterStatement.getQuery(), conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter();
param = cmd.Parameters.Add("#SeqName", SqlDbType.NVarChar);
param.Direction = ParameterDirection.Input;
param.Value = "SeqName";
SqlDataReader reader = cmd.ExecuteReader();
I have also tried using a DataSet to retrieve the return value with the same result. What am I missing to get
the return value from my stored procedure? If more information is needed, please let me know.
You need to add a ReturnValue-direction parameter to the command:
using (SqlConnection conn = new SqlConnection(getConnectionString()))
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = parameterStatement.getQuery();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("SeqName", "SeqNameValue");
// #ReturnVal could be any name
var returnParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
conn.Open();
cmd.ExecuteNonQuery();
var result = returnParameter.Value;
}
Setting the parameter's direction to ParameterDirection.ReturnValue instructs the SqlCommand to declare it as a variable and assign the stored procedure's return value to it (exec #ReturnValue = spMyProcedure...), exactly like you would write it in SQL.
I know this is old, but i stumbled on it with Google.
If you have a return value in your stored procedure say "Return 1" - not using output parameters.
You can do the following - "#RETURN_VALUE" is silently added to every command object. NO NEED TO EXPLICITLY ADD
cmd.ExecuteNonQuery();
rtn = (int)cmd.Parameters["#RETURN_VALUE"].Value;
The version of EnterpriseLibrary on my machine had other parameters.
This was working:
SqlParameter retval = new SqlParameter("#ReturnValue", System.Data.SqlDbType.Int);
retval.Direction = System.Data.ParameterDirection.ReturnValue;
cmd.Parameters.Add(retval);
db.ExecuteNonQuery(cmd);
object o = cmd.Parameters["#ReturnValue"].Value;
I had a similar problem with the SP call returning an error that an expected parameter was not included. My code was as follows.
Stored Procedure:
#Result int OUTPUT
And C#:
SqlParameter result = cmd.Parameters.Add(new SqlParameter("#Result", DbType.Int32));
result.Direction = ParameterDirection.ReturnValue;
In troubleshooting, I realized that the stored procedure was ACTUALLY looking for a direction of "InputOutput" so the following change fixed the problem.
r
Result.Direction = ParameterDirection.InputOutput;
This is a very short sample of returning a single value from a procedure:
SQL:
CREATE PROCEDURE [dbo].[MakeDouble] #InpVal int AS BEGIN
SELECT #InpVal * 2; RETURN 0;
END
C#-code:
int inpVal = 11;
string retVal = "?";
using (var sqlCon = new SqlConnection(
"Data Source = . ; Initial Catalog = SampleDb; Integrated Security = True;"))
{
sqlCon.Open();
retVal = new SqlCommand("Exec dbo.MakeDouble " + inpVal + ";",
sqlCon).ExecuteScalar().ToString();
sqlCon.Close();
}
Debug.Print(inpVal + " * 2 = " + retVal);
//> 11 * 2 = 22
ExecuteScalar(); will work, but an output parameter would be a superior solution.
You can try using an output parameter. http://msdn.microsoft.com/en-us/library/ms378108.aspx
Or if you're using EnterpriseLibrary rather than standard ADO.NET...
Database db = DatabaseFactory.CreateDatabase();
using (DbCommand cmd = db.GetStoredProcCommand("usp_GetNewSeqVal"))
{
db.AddInParameter(cmd, "SeqName", DbType.String, "SeqNameValue");
db.AddParameter(cmd, "RetVal", DbType.Int32, ParameterDirection.ReturnValue, null, DataRowVersion.Default, null);
db.ExecuteNonQuery(cmd);
var result = (int)cmd.Parameters["RetVal"].Value;
}
I see the other one is closed. So basically here's the rough of my code. I think you are missing the string cmd comment. For example if my store procedure is call:DBO.Test. I would need to write cmd="DBO.test". Then do command type equal to store procedure, and blah blah blah
Connection.open();
String cmd="DBO.test"; //the command
Sqlcommand mycommand;

SCOPE_IDENTITY is not working in asp.net?

I am trying to insert a record and get its newly generated id by executing two queries one by one, but don't know why its giving me the following error.
Object cannot be cast from DBNull to other types
My code is as below: (I don't want to use sql stored procedures)
SqlParameter sqlParam;
int lastInsertedVideoId = 0;
using (SqlConnection Conn = new SqlConnection(ObjUtils._ConnString))
{
Conn.Open();
using (SqlCommand sqlCmd = Conn.CreateCommand())
{
string sqlInsertValues = "#Name,#Slug";
string sqlColumnNames = "[Name],[Slug]";
string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + ");";
sqlCmd.CommandText = sqlQuery;
sqlCmd.CommandType = CommandType.Text;
sqlParam = sqlCmd.Parameters.Add("#Name", SqlDbType.VarChar);
sqlParam.Value = txtName.Text.Trim();
sqlParam = sqlCmd.Parameters.Add("#Slug", SqlDbType.VarChar);
sqlParam.Value = txtSlug.Text.Trim();
sqlCmd.ExecuteNonQuery();
//getting last inserted video id
sqlCmd.CommandText = "SELECT SCOPE_IDENTITY() AS [lastInsertedVideoId]";
using (SqlDataReader sqlDr = sqlCmd.ExecuteReader())
{
sqlDr.Read();
lastInsertedVideoId = Convert.ToInt32(sqlDr["lastInsertedVideoId"]);
}
}
}
//tags insertion into tag table
if (txtTags.Text.Trim().Length > 0 && lastInsertedVideoId > 0)
{
string sqlBulkTagInsert = "";
string[] tags = txtTags.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (string tag in tags)
{
sqlBulkTagInsert += "INSERT INTO tags(VideoId, Tag) VALUES(" + lastInsertedVideoId + ", " + tag.Trim().ToLowerInvariant()+ "); ";
}
using (SqlConnection Conn = new SqlConnection(ObjUtils._ConnString))
{
Conn.Open();
using (SqlCommand sqlCmd = Conn.CreateCommand())
{
string sqlQuery = sqlBulkTagInsert;
sqlCmd.CommandText = sqlQuery;
sqlCmd.CommandType = CommandType.Text;
sqlCmd.ExecuteNonQuery();
}
}
}
And also if possible, please check is the above code coded well or we can optimize it more for improve performance?
Thanks
The call to SCOPE_IDENTITY() is not being treated as being in the same "scope" as the INSERT command that you're executing.
Essentially, what you need to do is change the line:
string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + ");";
to:
string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + "); SELECT SCOPE_IDENTITY() AS [lastInsertedVideoId]";
and then call
int lastVideoInsertedId = Convert.ToInt32(sqlCmd.ExecuteScalar());
instead of .ExecuteNonQuery and the code block following the "//getting last inserted video id" comment.
The SCOPE_IDENTITY() should be extracted from the first command (SELECT, RETURN or OUT) and passed into the next command. By that, I mean that the SELECT_IDENTITY() should be at the end of the first command. In SQL 2008 there is additional syntax for bring values back as part of the INSERT, which makes this simpler.
Or more efficiently: combine the commands into one to avoid round-trips.

Categories