Fluent NHibernate Oracle function - c#

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 ...

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());

Why calling SP with parameters to return multiple resultsets in Entity Framework throws error

I have a stored procedure which has 2 input parameters and returns multiple result set.
ALTER PROCEDURE [dbo].[sp_GetList]
#eid int,
#sid int,
AS
SELECT ID, NAME FROM EMPLOYEE WHERE id=#eid;
SELECT ID, NAME FROM STUDENTS WHERE id=#sid
In entity framework I am calling this stored procedure as below.
I am using this tutorial from msdn.
https://msdn.microsoft.com/en-us/library/jj691402(v=vs.113).aspx
using (var db = new APIContext()) {
db.Database.Initialize(force: false);
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "[dbo].[sp_GetList]";
DbParameter eid = cmd.CreateParameter();
eid.ParameterName = "#eid";
eid.DbType = System.Data.DbType.Int32;
eid.Direction = ParameterDirection.Input;
eid.Value = resourceID;
DbParameter sid = cmd.CreateParameter();
sid.ParameterName = "#sid";
sid.DbType = System.Data.DbType.Date;
sid.Direction = ParameterDirection.Input;
sid.Value = sid;
cmd.Parameters.Add(sid);
try
{
db.Database.Connection.Open();
var reader = cmd.ExecuteReader();
EmpList = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Shared.Model.EmpList>(reader).ToList();
MList.EmpList = EmpList;
reader.NextResult();
SList = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Shared.Model.SList>(reader).ToList();
MList.SList = SList;
}
finally
{
db.Database.Connection.Close();
}
When I run this code, I get error:
Additional information: Procedure or function 'sp_GetList' expects parameter '#eid', which was not supplied.
I understand this is very basic error when it comes to ado.net, but this is different using Entity framework.
Any help is apreciated.
Your code seems to be missing:
cmd.Parameters.Add(eid);

Pass Array as parameter to Oracle stored proc from c# to bulk insert

I am trying to send arrays as parameter to Oracle stored proc in order to process bulk insert.
type Licensingentity_id is table of odilic_admin.licensingentity.licensingentity_id%type index by pls_integer;
type Nationalprovidernumber is table of odilic_admin.licensingentity.nationalprovidernumber%type index by pls_integer;
type Home_state_province_id is table of odilic_admin.licensingentity.home_state_province_id%type index by pls_integer;
procedure HomeStateLookup_bulk_insert(i_entityId in Licensingentity_id,
i_npn in Nationalprovidernumber,
i_homeStateId in Home_state_province_id) is
v_caller varchar2(60) := 'System_Scheduler';
begin
FORALL i IN 1 .. i_entityId.count
insert into home_state_lookup_stg
(licensingentity_id,
npn,
home_state_province_id,
isprocessed,
inserted_by,
inserted_date,
updated_by,
updated_date)
values
(i_entityId(i),
i_npn(i),
i_homeStateId(i),
0,
v_caller,
sysdate,
v_caller,
sysdate);
end HomeStateLookup_bulk_insert;
and here is the c# code
NiprConnectionString = ConfigurationManager.ConnectionStrings["ODI.NIPR.DB.Reader"].ConnectionString;
OracleConnection cnn = new OracleConnection(NiprConnectionString);
cnn.Open();
OracleCommand cmd = cnn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = NaicStateLookupRepositoryProcedures.HOME_STATE_BULK_INSERT;
cmd.BindByName = true;
cmd.ArrayBindCount = entities.Count;
var i_entityId = new OracleParameter();
var i_npn = new OracleParameter();
var i_homeStateId = new OracleParameter();
i_entityId.OracleDbType = OracleDbType.Int32;
i_npn.OracleDbType = OracleDbType.Varchar2;
i_homeStateId.OracleDbType = OracleDbType.Int32;
i_entityId.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
i_npn.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
i_homeStateId.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
i_entityId.Value = entities.Select(c => c.Key).ToArray();
i_npn.Value = entities.Select(c => c.Value.Item1).ToArray();
i_homeStateId.Value = entities.Select(c => c.Value.Item2).ToArray();
i_entityId.Size = entities.Count;
i_npn.Size = entities.Count;
i_homeStateId.Size = entities.Count;
cmd.Parameters.Add(i_entityId);
//cmd.Parameters[0].Value = i_entityId;
cmd.Parameters.Add(i_npn);
//cmd.Parameters[1].Value = i_npn;
cmd.Parameters.Add(i_homeStateId);
//cmd.Parameters[2].Value = i_homeStateId;
int result = cmd.ExecuteNonQuery();
but getting an exception -
ORA-06550: line 1, column 52: PLS-00103: Encountered the symbol ">"
when expecting one of the following:
( ) - + case mod new not null
Any help is much appreciated.
I can't promise this is the answer, and I don't have the tables you reference to test this for myself, but at first glance I noticed you set:
cmd.BindByName = true;
As such, I think you need to declare your parameter names:
var i_entityId = new OracleParameter("i_entityId");
var i_npn = new OracleParameter("i_npn");
var i_homeStateId = new OracleParameter("i_homeStateId");
I've never passed an array as a parameter to a procedure, but if you were to do this with a normal insert, it would look something like this:
string sql = "insert into foo values (:boo, :bar, :baz)";
OracleCommand cmd = new OracleCommand(sql, conn);
cmd.Parameters.Add(new OracleParameter("boo", OracleDbType.Varchar2));
cmd.Parameters.Add(new OracleParameter("bar", OracleDbType.Date));
cmd.Parameters.Add(new OracleParameter("baz", OracleDbType.Varchar2));
cmd.Parameters[0].Value = booArray;
cmd.Parameters[1].Value = barArray;
cmd.Parameters[2].Value = bazArray;
cmd.ArrayBindCount = booArray.Length;
cmd.ExecuteNonQuery();
I would start by defining the parameters with the parameter names, though.

.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();
}

Pervasive SQL System Stored Procedure from ADO.NET error

I'm just trying to return a list of columns and their attributes through a system stored procedure. What documentation I have seems to say the below code should work, but I get "Pervasive.Data.SqlClient.Lna.k: [LNA][Pervasive][ODBC Engine Interface]Invalid or missing argument." on the execute. This is PSQL v11, .NET 4.5.
using (PsqlConnection conn = new PsqlConnection(cs))
{
PsqlCommand locationCmd = new PsqlCommand();
PsqlParameter tableParam = new PsqlParameter();
PsqlParameter returnParam = new PsqlParameter();
returnParam.Direction = ParameterDirection.ReturnValue;
locationCmd.CommandText = "psp_columns";
locationCmd.Connection = conn;
locationCmd.CommandType = CommandType.StoredProcedure;
locationCmd.Parameters.Add(tableParam).Value = table;
locationCmd.Parameters.Add(returnParam);
conn.Open();
locationCmd.ExecuteNonQuery();
}
I would think the problem is this line:
locationCmd.Parameters.Add(tableParam).Value = table;
You should set the value before adding the parameter, not afterwards.
tableParam.Value = table;
locationCmd.Parameters.Add(tableParam);
I don't know about Psql but for MSSQL normally you also need to define the parameter name as its found in the stored procedure, or at least that's what I do.
SqlParameter param = new SqlParameter("#tableParam", value);
The psp_Columns system stored procedure is defined as call psp_columns(['database_qualifier'],'table_name', ['column_name']). I know that it says the database qualifier is optional, but I think it's required. You could try passing an empty string for the qualifier. Something like:
using (PsqlConnection conn = new PsqlConnection(cs))
{
PsqlCommand locationCmd = new PsqlCommand();
PsqlParameter dbParam = new PsqlParameter();
PsqlParameter tableParam = new PsqlParameter();
PsqlParameter returnParam = new PsqlParameter();
returnParam.Direction = ParameterDirection.ReturnValue;
locationCmd.CommandText = "psp_columns";
locationCmd.Connection = conn;
locationCmd.CommandType = CommandType.StoredProcedure;
locationCmd.Parameters.Add(dbParam).Value = ""; //might need two single quotes ('')
locationCmd.Parameters.Add(tableParam).Value = table;
locationCmd.Parameters.Add(returnParam);
conn.Open();
locationCmd.ExecuteNonQuery();
}
You should try to get the information of the table SCHEMA using the provided GetSchema method from the Psqlconnection. I have searched a bit on their support site and it seems that this method is supported although I haven't find a direct example using the Tables collection.
This is just an example adapted from a test on mine on SqlServer, I don't have Pervasive install, but you could try if the results are the same
using(PsqlConnection cn = new PsqlConnection("your connection string here"))
{
cn.Open();
string[] selection = new string[] { null, null, table };
DataTable tbl = cn.GetSchema("Columns", selection);
foreach (DataRow row in tbl.Rows)
{
Console.WriteLine(row["COLUMN_NAME"].ToString() + " " +
row["IS_NULLABLE"].ToString() + " " +
row["DATA_TYPE"].ToString()
);
}
}
i was trying to figure this out as well, but with the tables procedure. even though the database and table names are optional, you still have to provide values. for optional parameters, pass in DBNull.Value
this worked for me:
PsqlCommand cm = new PsqlCommand();
cm.CommandText = "psp_tables";
cm.CommandType = CommandType.StoredProcedure;
cm.Connection = new PsqlConnection();
cm.Connection.ConnectionString = <your connection string>;
cm.Parameters.Add(":database_qualifier", DBNull.Value);
cm.Parameters.Add(":table_name", DBNull.Value);
cm.Parameters.Add(":table_type", "User table");

Categories