Nullable Table Valued Parameter in Stored Procedure - sql-server-2008

I have this procedure
CREATE PROCEDURE dbo.spProcedure1
#intArray as dbo.intArray READONLY
AS
BEGIN
-- ...
END
which use user type as a parameter
CREATE TYPE dbo.IntArray AS TABLE (IntValue int NULL)
and I am calling the procedure from the C# ASP.NET MVC 4 project
// creating empty SQL #IntArray parameter
var emptyIntDataTable = new DataTable();
emptyIntDataTable.Columns.Add("IntValue");
// calling stored procedure
return Database.SqlQuery<int>(
#"spProcedure1 #p1",
new SqlParameter("p1", (object)Utils.ToDataTable(m.IntArray) ?? emptyIntDataTable)
).ToList();
// ToDataTable method which is returning null
public static DataTable ToDataTable<T>(this IList<T> data)
{
if (data == null)
return null;
... // code omitted because it is not working yet
}
the error which is throwed when calling stored procedure is
The table type parameter 'p1' must have a valid type name.
How to pass an empty table value?
Passing the list instead of datatable throw following error
var emptyIntDataTable = new List<int>;
No mapping exists from object type System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] to a known managed provider native type.

In your code:
where it says:
return Database.SqlQuery<int>(
#"spProcedure1 #p1", new SqlParameter("p1",
(object)Utils.ToDataTable(m.IntArray) ?? emptyIntDataTable)
).ToList();
Change it to read:
return m.IntArray.Length > 0?
Database.SqlQuery<int>(#"spProcedure1 #p1",
new SqlParameter("p1",
(object)Utils.ToDataTable(m.IntArray))).ToList():
Database.SqlQuery<int>(#"spProcedure1")).ToList();
sample to show how to not pass table parameter
CREATE TYPE dbo.KeyIds]
AS TABLE(pkId int NOT NULL,
PRIMARY KEY CLUSTERED (pkId ASC)
WITH (IGNORE_DUP_KEY = OFF))
Go
-- ------------------------------
Create procedure testProc
#aIds dbo.keyIds readonly
as
Set NoCount On
if exists (select * from #aIds)
Select * from #aIds
else
Select 'No Aids passed in'
Go
-- ------------------------------
Exec dbo.testProc -- <--- Here I am NOT passing the #aids parameter
But, even though I am NOT passing the #aids parameter
it still works, and the subquery (select * from #aIds) still functions, and since it is an empty datatable the SP returns the empty message 'No Aids passed in'.
On the other hand, if you pass the parameter
Declare #MyIds dbo.keyIds
Insert #MyIds Values(1)
Insert #MyIds Values(2)
Insert #MyIds Values(3)
Insert #MyIds Values(4)
Insert #MyIds Values(5)
Exec dbo.testProc #MyIds -- <--- Here I AM passing the #aids parameter
it outputs the contents of the datatable parameter
C# code example...
public DataTable GetAccountTransactions(IEnumerable<int> accountIds)
{
const string procName = "FetchAccountTransactionData";
var acctIds = accountIds == null ?
new List<int>() : accountIds.ToList();
// -------------------------------------------------
var parms = DbParamList.Make();
// DbParamList is a List<IDbDataParameter>
// See here, ONLY ADD PARAMETER if list is NOT empty!
if (acctIds.Count > 0)
parms.AddSQLTableParm("aIds", acctIds);
try
{ // following constructs command obkect and calls SP
return Utilities.GetDataTable(schemaNm + "." +
procName, parms, copConn);
}
catch (SqlException dbX)
{
// Exception stuff
}
}
public class DbParamSortedList : SortedList<string,IDbDataParameter> { }

The alternative solution
prepare method for converting List<int> into dbo.IntArray type
public static DataTable IntArrayToDataTable(IEnumerable<int> ids)
{
if (ids == null)
return null;
DataTable table = new DataTable();
// datatable columns has to have same name as database type !
table.Columns.Add("IntValue", typeof(int));
foreach (int id in ids)
{
table.Rows.Add(id);
}
return table;
}
run sql stored procedure
var sqlParameters = new List<object>();
var parameter1 = Utils.IntArrayToDataTable(m.IntArray);
if (parameter1 != null)
sqlParameters.Add(new SqlParameter("intArray", parameter1)
// these variables are the key, without them it is not working
{
SqlDbType = SqlDbType.Structured,
TypeName = "dbo.IntArray"
});
else // parameter cannot be omitted !! even if all parameters are named !! otherwise parameter mismatch happens (in case of multiple parameters)
sqlParameters.Add(new SqlParameter("intArray", SqlDbType.Structured) { TypeName = "dbo.IntArray" });
var sqlQuery = "spProcedure1 #InArray";
return Database.SqlQuery<int>(sqlQuery, sqlParameters.ToArray()).ToList();

Related

Input string was not in a correct format, MySQL Entity Framework Core

I am getting errors when I try to send string parameters using EF Core in ASP.NET Core 5 and use EF MySQL 5.0.8. The error is Input string was not in a correct format.
I am using this EF Core Library:
https://dev.mysql.com/doc/connector-net/en/connector-net-entityframework60.html
If I send int parameters the solution below works fine.
MYSQL Procedure
CREATE DEFINER=`MYUSER`#`%` PROCEDURE `test_sp`(
IN param1 int,
IN param2 text
#I tried type text, varchar, char
)
BEGIN
SELECT 1 as id, param1 as parameter, 'this is Parameter 1 INT' as text
UNION
SELECT 2 as id, param2 as parameter, 'this is Parameter 2 VARCHAR' as text;
END
ASP.NET CORE 5 CLASS
public async Task<List<T>> ExecuteStoredProcedure(string nameProcedure, List<MySqlParameter> parameters = null)
{
try
{
using (var data = new ContextBase(_optionBuilder))
{
//Add Space to separate sp name of the parameters
nameProcedure += "(";
var count = parameters.Count;
int i = 0;
//Insert the parameters in the procedure name
for (i = 0; i < count; i++)
{
nameProcedure += parameters[i].ParameterName;
if(i + 1 < count)
{
nameProcedure += ", ";
}
else
{
nameProcedure += ")";
}
}
//Remove the last Comma from the query
var responseData = await data.Set<T>().FromSqlRaw<T>("CALL " + nameProcedure, parameters.ToArray()).AsNoTracking().ToListAsync();
return responseData;
}
}
catch (Exception ex)
{
ErrorLog error = new ErrorLog();
error.Error = ex.Message;
error.Description = "Error encountered DB Procedure Execute ***. Message:" + ex.Message + " when getting the Generic Procedure Execute";
error.Section = "RepositoryProcedureGenerics.cs";
error.Layer = "Infra";
error.Date = DateTime.Now;
await this.CreateError(error);
return null;
}
}
ASP.NET CORE CONTROLLER
public async Task<IActionResult> ExecProcedure([FromQuery(Name = "param1")] int param1, [FromQuery(Name = "param2")] string param2)
{
//Create the list of Parameters
List<MySqlParameter> listParameters = new List<MySqlParameter>();
//int par = 1;
//string par2 = "XXX";
listParameters.Add(new MySqlParameter("#param1", MySqlDbType.Int32));
//I TRIED MySqlDbType.Text, MySqlDbType.VarChar and MySqlDbType.VarString
listParameters.Add(new MySqlParameter("#param2", MySqlDbType.Text));
listParameters[0].Value = param1;
listParameters[1].Value = param2;
string sp_name = "test_sp";
//Execute the Procedures
List<Test> test = await _procedureExecutor.ExecuteStoredProcedure(sp_name, listParameters.ToList());
return Ok();
}
Does someone knows where is my mistake?

Fat-Free-Framework / F3 access a hive variable in a mapper callback

I'm using the Fat Free Framework ORM Mapper functionality to insert a set of records passed from the client in an array. The Mapper function has callbacks to for aftersave which pass an array of keys and the mapper object.
I want to be able to loop through the records and use the mapper to insert the records one by one, storing the inserted record's id in an array ('resultsArray') which is set in the F3 hive in the parent function:
function myFunction (\Base $f3, $params) {
// array of records to insert
$mappedArray = json_decode( $f3->get('BODY'), true );
$f3->set('mapper', new mapper($db,'mytable'));
$mapper = $f3->get('mapper');
// create an array in the hive to store the results of the inserts
$f3->set('resultsArray', array());
// set mapper callbacks
$mapper->aftersave(function($self,$pkeys){
// update the resultsArray in the hive?
});
$recordsInArray = count($mappedArray);
// loop through the array of objects
for ($loop = 0; $loop<$recordsInArray; $loop++){
$newRecord = $mappedArray[$loop];
try{
// clear the mapper down
$mapper->reset();
// set the array in the hive
$f3->set('data', $newRecord );
$mapper->copyFrom('data');
$mapper->save();
} catch(\PDOException $e) {
// do something
exit;
}
}
echo "done";
}
Is there a way to access the resultsArray variable I set in the hive in the aftersave callback?
Thanks
Matt
Are you sure that you need to do all these things to achieve what you want?
To be able to store the IDs of inserted records and put it in the F3's hive, I would do the following:
<?php
function myFunction (\Base $f3, $params) {
// array of records to insert
$mappedArray = json_decode( $f3->get('BODY'), true );
//mapper (no need to put it into hive):
$mapper = new mapper($db,'mytable');
// array with IDs:
$resultsArray = [];
// loop through the array of objects
for ($loop = 0; $loop<count($mappedArray); $loop++){
try{
// clear the mapper down
$mapper->reset();
// map the content (no need to put it in the hive):
$mapper->copyFrom($mappedArray[$loop]);
// insert new record:
$mapper->save();
// get the ID of the inserted record and put it in the array:
$resultsArray[] = $mapper->_id;
} catch(\PDOException $e) {
// do something
exit;
}
}
// put the array of IDs in the hive:
$f3->set("newIDs", $resultsArray);
}
You can access the hive within the aftersave handler with the php use feature:
function myFunction (\Base $f3, $params) {
// ...
$mapper->aftersave(function($self,$pkeys) use($f3) {
$f3->get('resultsArray');
});
}

mysql statement WHERE as unknown

I have this sql statement:
selectAllUsersByCriteria = connection.prepareStatement(
"SELECT * FROM Users WHERE ? = ?" );
And the follow method running the statement:
public ArrayList<User> getUsersByCriteria(String 1criteria, String 2criteria)
{
ArrayList<User> results = null;
ResultSet resultSet = null;
try
{
selectAllUsersByCriteria.setString( 1, 1criteria);
selectAllUsersByCriteria.setString( 2, 2criteria);
// executeQuery returns ResultSet containing matching entries
resultSet = selectAllUsersByCriteria.executeQuery();
results = new ArrayList< User >();
while ( resultSet.next() )
{
results.add( new User( resultSet.getString( "userName" ),
resultSet.getString( "Password" ),
resultSet.getBoolean( "AdminRights" ),
resultSet.getDouble( "Balance" )
) );
} // end while
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
finally
{
try
{
resultSet.close();
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
close();
} // end catch
} // end finally
return results;
}
It doesn't work. I figure it is the first ? that is the issue. Isn't it possible to set the WHERE ? as a ?. Can it be solved in another way.
It is a table I want to show, but it should only be show the users follow it meet the two criteria.
You would need to inject the column name directly into the string. That would open you up to a SQL injection attack, so I'd recommend querying (and probably caching) the table's schema info (specifically found in INFORMATION_SCHEMA.COLUMNS).
This way you can make sure that your user-submitted column name matches one of the column names in your table before injecting it into the script by seeing if it's in your list of available columns.

if not then exit function

I see some java code does a cleaner way to exit as shown in this code.
if(a!=1) {System.exit();}
//If equal 1, execute the code below
Is there any similar keyword for Actionscript to stop a function (not exit a loop or application) as alternative to break keyword?
private function isInt():void {
if(a!=1) { /* stop executing the code after these */ }
b=a;
}
The Java code you quote exits the entire process - it stops executing. Flash runs inside a host process such as a web browser which should not be arbitrarily shut down - what if the user had content on other tabs?
If you specifically wanted to send a signal to the hosting browser, you should use fscommand or the newer mechanisms and let the browser/web page decide what to do.
If you just want to prevent any more execution of your function, just use 'return;' to leave the function you're in without doing any more processing.
Using a conditional return statement may seem clean and beautiful at first, but it can become a problem when refactoring, because it doesn't show its intent clearly.
What you are trying to say is this:
if my conditions are met, execute the next statement.
But what you are saying is:
if my conditions are not met, get out of here.
Example #1
Say you have a complex method with two or three nested if statements:
function myComplexMethod ( param1 : int, param2 : int, param3 : String ) : String {
var ret:String = null;
if (param3 != null) {
ret = param3;
if (param2 != 0) {
ret += param2;
if (param3 != 0) {
ret += param1 + param2;
}
}
}
return ret;
}
Example #2
Of course, the same method would look better using conditional return statements:
function myComplexMethod ( param1 : int, param2: int, param3:String ) : String {
if (!param3) return null;
var ret : String = null;
ret += param3;
if (param2 == 0) return ret;
ret += param2;
if (param1 == 0) return ret;
ret += param1 + param2;
return ret;
}
But at first glance, can you really tell what the output of this method is going to be?
Example #3
What if you were going to really clean up your code? If you refactored the code to reflect the intent of each block, the complex method would become a simple method:
function mySimpleMethod ( param1 : int, param2: int, param3:String ) : String {
return param3 != null ?
outputOfAllParams (param1, param2, param3 ) : null;
}
function outputOfAllParams ( param1 : int, param2: int, param3:String ) : String {
return param2 != 0 ?
param3 + combinedOutputOfIntParams ( param1, param2 ) : param3;
}
function combinedOutputOfIntParams ( param1 : int, param2: int ) : String {
return param1 != 0 ?
param2 + "" + sumOfIntParams( param1, param2) : "" + param2;
}
function sumOfIntParams( param1 : int, param2: int ) : int {
return param1 + param2;
}
In this last example, the code is easily readable, and you can see what it is supposed to do by just looking at it.
The thing is: You could easily use refactoring to get from example #1 to example #3 - it is obvious that each of the conditional blocks will be refactored to a new method. With the conditional return statements, it is far less intuitive: You'll have to check very carefully, where the desired code block ends, and when to return what.
Of course, if you're dealing with simple tasks like this, the benefits are not as obvious, but if you had real production code, you definitely want the intent as obvious as possible, and even if you were coming back to your own code in a couple of months, it would take you much longer to understand what it is supposed to do, if you used example #2.

not able to call methods after decoding from json

I have a Lua class like below. I am using json to serialize the object and put it in a key value store. I am able to serialize the object and put it in the key value store successfully but i am not able to call any methods of the object after i retrieve the object from the key value store. I understand the json module skips the methods while encoding and my object does not have methods after decoding.
Is there a way to append methods to the class after i decode the object from json to lua ? some thing similar to function pointers in C language.
local class_name = "user_object";
user_object = {}; --user class
function user_object.new (mobile, password, uid)
local self = {};
self.mobile = mobile;
self.uid = uid; -- generate a uid which is a running number.
self.password = password;
self.messages_sent = 0;
self.put_request_count = 0;
self.get_request_count = 0;
self.last_time_active = "";
self.get_tickets = {};
self.put_tickets = {};
self.group_message_stream = {};
self.group_ownerships = {}; -- group names which he is owner of
self.group_memberships = {}; -- group names which he is member of
self.sent_poke_count = 0;
self.sent_poke_stream = {};
self.recv_poke_count = 0;
self.recv_poke_stream = {};
function self:add_put_ticket(ticketid)
table.insert(self.put_tickets, ticketid);
self:incr_put_count();
self:save();
return;
end
function self:add_get_ticket(ticketid)
table.insert(self.get_tickets, ticketid);
self:incr_get_count();
self:save();
return;
end
Function in Lua are first class objects, you can store a function in any variable. The line
function self:add_put_ticket(ticketid)
is equivalent to
self.add_put_ticket = function (self, ticketid)
From there, it should be obvious what to do: define your desired methods where they are accessible and assign them to the appropriate fields after deserialization
You can do this with metatables.
user = { name = 'ponzao' } -- Just a table with values.
User = {} -- Table containing the functions.
function User:allCapsName() return self.name:upper() end -- A method.
setmetatable(user, {__index = User}) -- For unavailable keys all calls are dispatched to User.
print(user:allCapsName()) --> "PONZAO"