ExecuteSqlCommand return -1? - ef-core-2.1

I am trying to call a stored procedure from code , in ef core 2 i found that i can use context.database.ExecuteSqlCommand() function to execute any stored procedure in my database.
While the stored procedure works fine in my sql server instance :
calling it from my code , returns -1 result !?:
using (var context = new AZPDBDEMOGZContext(optionsBuilder.Options))
{
var existUser = context.Database.ExecuteSqlCommand("GetIdUsager_ByNomPrenomEmail #p0,#p1,#p2", parameters:new[] { "rouarouarouarouaroua", "wiem", "test#gmail.com" });
}
what m i doping wrong ?

ExecuteSqlCommand will only return a 'rows affected' integer for a DML query aka insert/update/delete. Your stored proc looks like its returning a result set so it returns -1 as you've not provided a statement that changes the data source. You'll need to create a POCO and use FromSql to populate it.

Related

Node.js sequelize calling a stored procedure with input and output parameters

Database Query :
CREATE DEFINER=`root`#`localhost` PROCEDURE `signinVendor`(in inputvalue varchar(100), in pword varchar(30), **out retval tinyint**)
BEGIN
Node.js Code :
const spquery = await db.sequelize.query('call signinVendor(:inputvalue,:pword,**#retval**);',{
replacements:{
inputvalue : req.body.inputvalue,
pword : req.body.password
},
type: QueryTypes.SELECT,
raw: true
});
I am able to call procedures by entering the input value and password. But, I am unable to find syntax to access the return value through my sequelize nodejs code. How do we write code for out parameter in sequelize?
Okay it seems that we can pre write code and send output via select in database and avoid using output parameter. It seems Sequelize ORM has not yet implemented any way to accesss the output parameter through NodeJS.
FOR EXAMPLE:
IN SQL,
instead of creating an out parameter in stored procedure, you can use parameters to store your desired output.
set query = (select count(*) from table_name);
Then you can perform select without parameter like :
select query ;
This way you don't need to rely on output parameter in Sequelize ORM. You can simply select your desired output as the outcome of the stored procedure.

SimpleJdbcCall for MySql Function yields "Can't set IN parameter for return value of stored function call"

Using the example from the Spring docs, I'm trying to return a value from a mySQL function. I keep getting the error Can't set IN parameter for return value of stored function call;.
I created a mySQL function that works fine (ran in MySQL Workbench). I've written a SimpleJdbcCall statement, set up the parameters as per Spring docs example but consistently get this error. If I turn the function into a procedure, the code works, I just have to retrieve the return value from the result set.
I used https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch13s05.html, section 13.5.8 as reference.
CREATE FUNCTION `ScenarioRegistration`(
environment VARCHAR(45),
username VARCHAR(15),
scenario_name VARCHAR(45)) RETURNS int(11)
A couple of SELECT statements followed by an INSERT then
RETURN scenario_id; // The inserted id
Java code:
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getJdbcTemplate())
.withFunctionName("ScenarioRegistration")
.withoutProcedureColumnMetaDataAccess();
simpleJdbcCall.addDeclaredParameter(new SqlParameter("environment"
,Types.VARCHAR));
simpleJdbcCall.addDeclaredParameter(new SqlParameter("username"
,Types.VARCHAR));
simpleJdbcCall.addDeclaredParameter(new SqlParameter("scenario_name"
,Types.VARCHAR));
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("environment", environment)
.addValue("username", username)
.addValue("scenario_name", scenario);
simpleJdbcCall.setReturnValueRequired(true);
Integer scenario_id = simpleJdbcCall.executeFunction(
Integer.class, parameters);
All I want the routine to do is give me back the id of the newly inserted scenario.
What I get is:
SQL [{? = call scenarioregistration(?, ?)}]; Can't set IN parameter for return value of stored function call.
I find it interesting that it's taken my THREE input values and changed them to an output and TWO input values.
Anyone enlighten me as to the problem and how to fix it?
Thanks,
Steven.
I would refer to the latest docs here for your answer. It appears Spring is trying to infer the output because you didn't explicity specify one.
Per the docs above there are two valid approaches on calling the desired function with the SimpleJdbcCall:
Inferred Parameters
Because you've specified withoutProcedureColumnMetaDataAccess, Spring isn't going to look and see what the ins/outs are to your function. If you want it easy, just don't specify that and you should be able to do:
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("environment", environment)
.addValue("username", username)
.addValue("scenario_name", scenario);
Integer scenarioId = new SimpleJdbcCall(getJdbcTemplate())
.withFunctionName("ScenarioRegistration")
.executeFunction(Integer.class, parameters);
Explicit Parameters
If you want to keep withoutProcedureColumnMetaDataAccess turned off for whatever reason, you can do:
Integer scenarioId = new SimpleJdbcCall(getJdbcTemplate)
.withFunctionName("ScenarioRegistration")
.withoutProcedureColumnMetaDataAccess()
.useInParameterNames("environment", "username", "scenario_name")
.declareParameters(
new SqlOutParameter("scenario_id", Types.NUMERIC),
new SqlParameter("environment", Types.VARCHAR),
new SqlParameter("username", Types.VARCHAR),
new SqlParameter("scenario_name", Types.VARCHAR)
).executeFunction(Integer.class, parameters);
Note: It appears that order is critical in this example. The output parameter should be declared first, and the subsequent named IN parameters come last. That is, the order of the parameters ? are ordinal in [{? = call scenarioregistration(?, ?, ?)}])
Alternative NamedParameterJdbcTemplate Solution
Another way to invoke your function is via an actual JDBC call. This could hypothetically save you the grief of using the fine tuning of the SimpleJdbcCall.
Integer scenarioId = namedParameterJdbcTemplate.queryForObject(
"SELECT ScenarioRegistration(:environment, :username, :scenario_name)",
parameters,
Integer.class);

hsqldb procedure with date Input parameter

I need to write a test for some download operation. This operation call procedure from MSSQL database, take result set and java make some stuf. For test I use hsqldb.
My procedure:
CREATE PROCEDURE map.Get1(IN packageName varchar(100),
IN downloadDate DATE)
READS SQL DATA DYNAMIC RESULT SETS 1 BEGIN ATOMIC
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM map.tvschedule FOR READ ONLY;
OPEN result;
END
This procedure wan't work, i have an exception
call map.GET1('Genre','2018-03-10');
[42561][-5561] incompatible data type in conversion
java.lang.RuntimeException: org.hsqldb.HsqlException: incompatible data type
in conversion
But this(without date parameter) work well:
CREATE PROCEDURE map.Get1(IN packageName varchar(100))
READS SQL DATA DYNAMIC RESULT SETS 1 BEGIN ATOMIC
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM map.tvschedule FOR READ ONLY;
OPEN result;
END
call map.GET1('Genre');
first needed row
second needed row
I am not going to use input parameter, but i need this procedure to be looking i am going to.
My question is How to use date input parameter with hsqldb procedures?
UPDATE1:
I used TO_DATE and now it works well, but i have no data in my result set, my java code is:
try (CallableStatement callableStatement = connection.prepareCall("{ call
map.GetGenreProtocol( ?, ? ) }")) {
callableStatement.setString(1, packageName);
callableStatement.setDate(2, date);
callableStatement.execute();
ResultSet resultSet = callableStatement.getResultSet();
while (resultSet.next()) {
Interval Interval = new Interval();
Interval.setDuration(resultSet.getInt("duration"));
Interval.setMappingTargetId(resultSet.getInt("mappingTargetId"));
Interval.setGenreId(resultSet.getInt("genreId"));
Interval.setStart(resultSet.getLong("start"));
Interval.setCategoryId(resultSet.getInt("categoryId"));
Interval.setCategoryName(resultSet.getString("categoryName"));
Interval.setGenreName(resultSet.getString("genreName"));
Interval.setDescription(resultSet.getString("description"));
Intervals.add(Interval);
}
}
Use the TO_DATE function.
For example:
call map.GET1('Genre', TO_DATE('2018-03-10', 'YYYY-MM-DD'));
I guess you need to create a function that returns a table instead of a procedure:
CREATE FUNCTION map.Get1(IN packageName VARCHAR(100),
IN downloadDate DATE)
RETURNS TABLE(.....)
READS SQL DATA
BEGIN ATOMIC
....
END;

turn c# code into mysql function

I have the following code in C# that I would like to turn into a MySQL snippet instead?
foreach (DataRow row in dtBills.Rows)
{
classes.UtilityBill ub = new classes.UtilityBill(row);
if (ub.ApprovedBy > 0)
{
if (ub.RemainingBalance() > 0) { totalOutstanding += ub.RemainingBalance(); numberOfUnpaidBills++; }
if (ub.RemainingBalance() > 0 && ub.IsOverDue()) { numberOfOverdueBills++; }
}
else
{
if (ub.ApprovedBy == 0)
{
awaitingApproval++;
}
else
{
rejectedBills++;
}
}
}
ub.RemainingBlaance() basically checks two fields in the table and subtracts, amount_due - amount_paid
What I'm looking to have returned is a single row that looks something like:
totalOutstanding, numberOfUnpaidBills, numberOfOverdueBills, awaitingApproval, rejectedBills
Original table:
I know that this might come across like a lazy question, but I have never dealt with coding in mysql, just simple queries, and I have no idea on how to start. A push in the right direction would suffice, not a complete solution.
Thanks!
To query mysql you can use the mysql.data nuget package. You can look up their documentation. I created a nuget to simplify code from any c# framework to mysql as well. If you don't mind third party nugets, you can try it out. It is called mysql.simple. From what I understand from what the code is trying to do, here is a small code for pulling data:
using (Database db = ConnectionString) // initializes connection
{
// you can omit the below select function if you would like to select all
using (var Row = db.Select("unit_cost, start_reading")
From("tblName").Query()
while(Row.Read()){ // gets each row
ub.unit_cost = Row["unit_cost"];
ub.start_reading= Row["start_reading"];
.
.
.
}
}
The db object above has select, update and insert functions with all variations including insert statements with selects. However if you would like to use raw sql queries, you can directly use db.Query("sql query here"). You can see more documentations here http://mysqlsimple.azurewebsites.net/docs
Here is a sample mySql stored procedure I had with me:
DELIMITER //
DROP PROCEDURE IF EXISTS proc_IF;
CREATE PROCEDURE proc_IF (IN param1 INT)
BEGIN
DECLARE variable1 INT;
SET variable1 = param1 + 1;
IF variable1 = 0 THEN
SELECT variable1;
END IF;
IF param1 = 0 THEN
SELECT 'Parameter value = 0' ;
ELSE
SELECT 'Parameter value <> 0' ;
END IF;
END //
This example contains parameters, variables and if statement examples.
You can call this in c# something like this:
db.QueryValue("CALL proc_IF (#0)", myVal);

How to pass an array of parameters to MySql select ... in

I wish to select an array of records with id 2, 4, 6 from a mysql database file. I am trying to pass an array of integers to a Mysql store procedure. But I fail to create a working stored procedure.
Would you help me compose one?
This is the C# code
public static List<PhotoComment> GetPhotos(int[] _ids)
{
MySqlConnection _con = Generals.GetConnnection();
List<PhotoComment> _comments = new List<PhotoComment>();
try
{
MySqlCommand _cmd = new MySqlCommand("Photos_GetPhotosByIDs", _con);
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.Parameters.AddWithValue("#_ids", _ids);
_con.Open();
MySqlDataReader _reader = _cmd.ExecuteReader();
while (_reader.Read())
{
PhotoComment _comment = new PhotoComment(_reader.GetInt32("cID"), _reader.GetInt32("cFID"), _reader.GetString("cUser"), _reader.GetString("cContent"), _reader.GetDateTime("cDate"), _reader.GetBoolean("cChecked"));
_comments.Add(_comment);
}
_con.Close();
}
catch (Exception _ex)
{
_con.Close();
ReportMgr.ReportException(_ex.Message);
}
return _comments;
}
this is the mysql
CREATE DEFINER=root#localhost PROCEDURE Photos_GetPhotosByIDs(in _ids int[])
BEGIN
select * from tbl_photos where ID in _ids;
END
There are no array types in MySQL. You can use table (temporary table) instead. Fill the bale with id values and join tables to get desired result.
I'm not sure if I'm getting your question right but what I think you're asking is how to send multiple values into an input parameter of a stored procedure.
If that's what you're asking, the following link may help. Not sure if such a feature exists in MySql but in SQL Server, it's called "Table-Valued Parameters" - TVP in short.
TVP allows you to pass multiple values into a single input parameter. Hope this helps: https://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx