How do you call an as400 stored procedure with oledb? - c#

I am trying to call a stored procedure from my code using oledb but I can't figure out how to do this. This is the code I wrote but it's not working
OleDbCommand sp = connectionDB.CreateCommand();
sp.CommandText = "CALL NASVARWG.§SP001('?','?','?','?','?','?')";
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 = "blah";
sp.Parameters["P3"].Size = 10;
sp.Parameters["P3"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P4", System.Data.OleDb.OleDbType.Char);
sp.Parameters["P4"].Size = 2;
sp.Parameters["P4"].Direction = ParameterDirection.Output;
sp.Parameters.Add("P5", System.Data.OleDb.OleDbType.Char);
sp.Parameters["P5"].Size = 256;
sp.Parameters["P5"].Direction = ParameterDirection.Output;
sp.Parameters.Add("P6", System.Data.OleDb.OleDbType.Char).Value = textBox_Reparto.Text;
sp.Parameters["P6"].Size = 6;
sp.Parameters["P6"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P7", System.Data.OleDb.OleDbType.Char).Value = "we can do this";
sp.Parameters["P7"].Size = 60;
sp.Parameters["P7"].Direction = ParameterDirection.Input;
sp.Parameters.Add("P8", System.Data.OleDb.OleDbType.Char).Value = "help";
sp.Parameters["P8"].Size = 256;
sp.Parameters["P8"].Direction = ParameterDirection.Input;
sp.Prepare();
sp.ExecuteNonQuery();
I get an exception at "sp.Prepare();" telling me that the syntax of the command is wrong.

If you can, use the IBM i Access ADO.NET drivers and place the program call in a stored procedure. They can convert the data from i to PC.

As #Syafiqur__ mentioned the ADO.NET drivers are a better choice.
And as always there is an IBM redbook about it. In my solutions I use the IBMDA400 version.
For your case it should look like this:
var command = new iDB2Command(cmdText: "§SP001", cmdType: CommandType.StoredProcedure, connection: masterSystemConnection);
var p1 = new iDB2Parameter(parameterName: "#P1", type: iDB2DbType.iDB2Char, size: 10);
p1.Direction = ParameterDirection.Input;
p1.Value = "ESANASTRIS";
command.Parameters.Add(p1);
// ... all your other parameters, no call to Prepare
command.ExecuteNonQuery();
Regarding your SQL0469:
Either change the attribute of the parameter on the DECLARE PROCEDURE, CREATE PROCEDURE, or ALTER PROCEDURE statement or change the parameter.
For additional details please have a look at the IBM documentation.
Bernd

I think your problem is most likely that you have NO parameter markers in your SQL statement.
sp.CommandText = "CALL NASVARWG.§SP001('?','?','?','?','?','?')";
The '?' are string constants, not parameter markers ? which should appear without apostrophes. So the statement should really look like this:
sp.CommandText = "CALL NASVARWG.§SP001(?, ?, ?, ?, ?, ?)";

Related

C# how to call “sp_executesql” with custom parameters and sql body

I am trying to execute a dynamic SQL from C# and I want to use sp_executesql because I want to pass a list of strings to be used for an IN statement in the dynamic SQL passed to sp_executesql.
The thing is that I don't know exactly how to do this.
So far I did it like this:
using (var dbCommand = databaseConnection.CreateCommand())
{
dbCommand.CommandType = CommandType.StoredProcedure;
dbCommand.CommandText = "sp_executesql";
var sqlParam = dbCommand.CreateParameter();
sqlParam.DbType = DbType.String;
sqlParam.ParameterName = "stmt";
sqlParam.Value = sql.SQL;
dbCommand.Parameters.Add(sqlParam);
var incidentIdParam = dbCommand.CreateParameter();
incidentIdParam.ParameterName = "incidentId";
incidentIdParam.DbType = DbType.Int32;
incidentIdParam.Value = arguments.filterAttributes.incidentId;
dbCommand.Parameters.Add(incidentIdParam);
dbCommand.ExecuteReader();
}
Is it possible like this?
As an option, you can format your SQL on the client side and pass to the stored procedure ready string. For example:
sql.SQL = "UPDATE ORDERS SET STATUS = 1 WHERE ID = %param%";
then
sqlParam.Value = sql.SQL.Replace("%param%", arguments.filterAttributes.incidentId.ToString());

Fluent NHibernate Oracle function

I'm currently using Fluent NHibernate ORM and trying to call oracle function fu_GetUserGrant. I have tried the code below:
var dbCommand = session.Connection.CreateCommand();
dbCommand.CommandText = "select fu_GetUserGrant(#grantId) from dual;";
dbCommand.CommandType = CommandType.Text;
var param = dbCommand.CreateParameter();
{
param.Value = grantId;
param.DbType = DbType.StringFixedLength;
param.Size = 200;
param.ParameterName = "#grantId";
}
dbCommand.Parameters.Add(param);
var result = dbCommand.ExecuteNonQuery();
return long.Parse(result.ToString());
And getting exception - Oracle.ManagedDataAccess.Client.OracleException : ORA-00936: missing expression
After several hours of failure I tried another approach:
var c = session.
CreateQuery("select fu_GetUserGrant(:grantId) from dual;")
.SetParameter("grantId", grantId).UniqueResult<int>();
and getting exception - NHibernate.Hql.Ast.ANTLR.QuerySyntaxException : dual is not mapped [select fu_GetUserGrant(:grantId) from dual;]
any ideas guys? When i retrieve same function from MSSQL it works fine (of course I use different sql query because of MSSQL.)
At first sample you are using SQL query and in second HQL query. In HQL query there is no dual of course. So what you should do is in SQL using ":" instead "#"
dbCommand.CommandText = "select fu_GetUserGrant(:grantId) from dual;"
So I managed to find answer to my problem.
To call oracle function i used code bellow:
var dbCommand = session.Connection.CreateCommand();
dbCommand.CommandType = CommandType.StoredProcedure;
dbCommand.CommandText = "fu_GetUserGrant";
var returnValue = dbCommand.CreateParameter();
{
returnValue.ParameterName = "Return_Value";
returnValue.DbType = DbType.Decimal;
returnValue.Direction = ParameterDirection.ReturnValue;
}
var grantIdParam = dbCommand.CreateParameter();
{
grantIdParam.Value = grantId;
grantIdParam.DbType = DbType.StringFixedLength;
grantIdParam.Size = 200;
grantIdParam.ParameterName = "m_In_GrantId";
grantIdParam.Direction = ParameterDirection.Input;
}
dbCommand.Parameters.Add(returnValue);
dbCommand.Parameters.Add(grantIdParam);
dbCommand.ExecuteReader();
return long.Parse(returnValue.Value.ToString());
What i learned is that, you can call oracle functions through CommandType.StoredProcedure; if you specify where will be put return value from the function, in this case was - var returnValue ...

.Net MySql User Defined Variable as Output Parameter

I've been searching for a while but the answers I find usually involve stored procedures or different functionality.
I am trying to execute a reader and also return a scalar in the one query. I thought I could do this using an output parameter, but I get an exception to check my syntax near NULL = #rows_found(), so it appears the output parameter is not getting initialized.
Basically I need to know if this is possible as I haven't found a code sample like this that works.
command.CommandText = #"
SELECT SQL_CALC_FOUND_ROWS
accounting.*
FROM
accounting
WHERE
transaction_type = #transaction_type
LIMIT
#index, #results;
SET #total_rows = FOUND_ROWS();
";
command.Parameters.AddWithValue("transaction_type", transaction_type);
command.Parameters.AddWithValue("index", index);
command.Parameters.AddWithValue("results", results);
MySqlParameter totalRows = new MySqlParameter("total_rows", 0);
totalRows.Direction = System.Data.ParameterDirection.Output;
command.Parameters.Add(totalRows);
using (MySqlDataReader dr = command.ExecuteReader())
{
while (dr.Read())
invoices.Add(new AccountingDataModel(dr));
}
invoices.Total = (int)totalRows.Value;
cmd.Parameters["#output"].Value.ToString()
Use command object to access your out parameter ....
you can not access out perameter directly.
You Should use like
invoices.Total = Convert.ToInt32(command.Parameters["total_rows"].Value.ToString())
example for stored procedure
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
return Convert.ToInt32(cmd.Parameters["#output"].Value.ToString());
It seems that this is not possible. From the documentation of MySqlParameter's members for the Direction property:
Gets or sets a value indicating whether the parameter is input-only, output-only, bidirectional, or a stored procedure return value parameter. As of MySQL version 4.1 and earlier, input-only is the only valid choice.
So the parameter is, no matter what you set Direction to, always an input parameter. If you change the value from null to anything else (e.g. 15) you should see that the generated query is something like
SET 15 = FOUND_ROWS()
Eventually i ended up running two queries. Probably this is not as performant as it could be, but at least it gets the desired result (using EF Core):
using (var context = new MyDbContext(...))
{
context.Database.OpenConnection();
var estates = context.MySet
.FromSql("SELECT SQL_CALC_FOUND_ROWS * FROM myset LIMIT 25 OFFSET 25")
.ToList();
var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "SELECT FOUND_ROWS()";
var rows = (long)cmd.ExecuteScalar();
context.Database.CloseConnection();
}

Can't get it! SqlParameter with ParameterName is not contained by this SqlParameterCollection. Stored proc param

I know that this question has been asked many times, And I have read many many answers, yet I can't figure out what is wrong. It's been hours. Any help would be soo appreciated. I am just trying to call a stored procedure in an ASP page, and I am unable to add the parameter properly, getting the exception that it is not in the collection.
I have modified my proc as follows to try to make it simple and isolate the issue.
ALTER PROCEDURE [dbo].[up_validateUserWithClinicCount]
#HTID INT = 0,
#ValidUserID INT OUTPUT,
#MultiClinicFlag INT OUTPUT
AS
DECLARE #vClinicCount INT = null
DECLARE #vUserValid INT = null
BEGIN
SET #ValidUserID = 2
SET #MultiClinicFlag = 1
END;
AND the C# code
String connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["PC3PaymentConnection"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand cmd = new SqlCommand("up_validateUserWithClinicCount", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#HTID", htId);
SqlParameter uidOut = new SqlParameter("#ValidUserID", SqlDbType.Int);
uidOut.Size = 4;
uidOut.Direction = ParameterDirection.Output;
cmd.Parameters.Add(uidOut);
SqlParameter pMultiClinics = new SqlParameter();
pMultiClinics.ParameterName = "#MultiClinicFlag";
pMultiClinics.SqlDbType = SqlDbType.Int;
pMultiClinics.Direction = ParameterDirection.Output;
cmd.Parameters.Add(pMultiClinics);
try
{
cmd.ExecuteNonQuery();
//--> Error points to the next line, and I have tried to use int.parse rather than convert also, with the same error -- parameter not in collection
MultiClinics = Convert.ToInt16(cmd.Parameters["pMultiClinics"].Value);
PC3User = Convert.ToInt16(uidOut.Value.ToString());
}
catch (SqlException sqlEx)
{
LbMsg.ForeColor = System.Drawing.Color.Red;
LbMsg.Text = sqlEx.Message;
}
}
}
Thanks if you can see what I am missing.
You have an object reference for the parameter already, you don't need to grab it from the parameters collection. Also, sql ints are 32-bit.
MultiClinics = (int)pMultiClinics.Value;
To retrieve from the parameter collection, use the ParameterName you gave it:
MultiClinics = (int)cmd.Parameters["#MultiClinicFlag"].Value;

Defining SQL parameters for INSERT Statement in C#

I have created a parameterized SQL insert query and I have made a mistake somewhere. I kept getting a message that values would be truncated, so, during troubleshooting I reduced the query to only fields that required values (NULLs not allowed), and the insert statement completed.
I check the table, and I see my parameter names inserted, not the values they should be pulling from the form's textboxes.
Obviously I am calling my parameters incorrectly but I just can't figure out where I have gone wrong. I am hoping you all can help me.
Thanks in advance!
NOTE: Yes, I know there are more parameters than what I am using in the INSERT string. I have intentionally cut down the values used for troubleshooting.
Thanks again!
try {
string InsertString = #"INSERT INTO Item.Itemtable
(ItemNumber, ItemDesc, RatioToOriginalItemNumber, OriginalItemNumber, EntreeCount, ItemType, ProteinBeverage)
Values(#ItemNumberValue, '#ItemDescValue', #RatioToOriginalItemNumberValue, #OriginalItemNumberValue, #EntreeCountValue, '#ItemTypeValue', #ProteinBeverageValue)";
SqlCommand InsertNewItem = new SqlCommand(InsertString, PmixWriter);
//Define Insert Parameters
SqlParameter #ItemNumberValue = InsertNewItem.Parameters.Add("#ItemNumberValue", System.Data.SqlDbType.Int);
SqlParameter #ItemDescValue = InsertNewItem.Parameters.Add("#ItemDescValue", System.Data.SqlDbType.VarChar, 100);
SqlParameter #ItemTypeValue = InsertNewItem.Parameters.Add("#ItemTypeValue", System.Data.SqlDbType.VarChar, 100);
SqlParameter #ProteinBeverageValue = InsertNewItem.Parameters.Add("#ProteinBeverageValue", System.Data.SqlDbType.VarChar, 100);
SqlParameter #IsCouponValue = InsertNewItem.Parameters.Add("#IsCouponValue", System.Data.SqlDbType.Char, 3);
SqlParameter #EntreeCountValue = InsertNewItem.Parameters.Add("#EntreeCountValue", System.Data.SqlDbType.Real);
SqlParameter #BevCountValue = InsertNewItem.Parameters.Add("#BevCountValue", System.Data.SqlDbType.TinyInt);
SqlParameter #OriginalItemNumberValue = InsertNewItem.Parameters.Add("#OriginalItemNumberValue", System.Data.SqlDbType.Int);
SqlParameter #RatioToOriginalItemNumberValue = InsertNewItem.Parameters.Add("#RatioToOriginalItemNumberValue", System.Data.SqlDbType.TinyInt);
SqlParameter #FPBeverageCountValue = InsertNewItem.Parameters.Add("#FPBeverageCountValue", System.Data.SqlDbType.Int);
SqlParameter #FPBeverageEntreeCountValue = InsertNewItem.Parameters.Add("#FPBeverageEntreeCountValue", System.Data.SqlDbType.Int);
SqlParameter #FoodCostValue = InsertNewItem.Parameters.Add("#FoodCostValue", System.Data.SqlDbType.Money);
//Assign and covert values to the stated SQL parameters.
#ItemNumberValue.Value = Convert.ToInt32(ItemNumberBox.Text);
#ItemDescValue.Value = ItemDescBox.Text;
#ItemTypeValue.Value = ItemTypeBox.Text;
#ProteinBeverageValue.Value = ProteinBevBox.Text;
#IsCouponValue.Value = IsCouponBox.Text;
#EntreeCountValue.Value = Convert.ToInt32(EntreeCountBox.Text);
#BevCountValue.Value = Convert.ToInt32(BevCountBox.Text);
#OriginalItemNumberValue.Value = Convert.ToInt32(OriginalItemNumBox.Text);
#RatioToOriginalItemNumberValue.Value = Convert.ToInt32(RatioBox.Text);
#FPBeverageCountValue.Value = Convert.ToInt32(FPBevBox.Text);
#FPBeverageEntreeCountValue.Value = Convert.ToInt32(FPBevEntreeBox.Text);
#FoodCostValue.Value = Convert.ToDecimal(0.00);
InsertNewItem.ExecuteNonQuery();
} catch (SqlException) {
throw;
}
In your INSERT statement, remove the single quotes from #ItemDescValue and #ItemTypeValue parameters. They are currently being inserted as literal values otherwise.

Categories