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?
I want to use datepicker to select range of dates. This range of dates is then queried in the database where the sum is counted...
My attempt:
public static int dateRange(){
int value = 0;
PreparedStatement stmt = null;
try {
Connection connection = DriverManager.getConnection("", "", "");
stmt = connection.prepareStatement("SELECT SUM(cost) FROM Items WHERE expiration_date between '" + Budget.datePicker1.getValue() + "' and '" + Budget.datePicker2.getValue() + "'");
ResultSet result = stmt.executeQuery();
result.next();
String sum = result.getString(1);
value = Integer.parseInt(sum);
} catch (Exception e){
value += 0;
}
return value;
}
It works. It returns the total if the days are there so to speak. If there are no days in the database as selected in the DatePicker then 0 pops up... But it looks messed up (catch block) and I was wondering if anyone could help me with an alternative solution?
First, since the value returned by the query is an integer value, there is no need to read it as a string and parse it. Just use result.getInt(...).
Second, if you are going to use a PreparedStatement, use it to properly set parameters, instead of building the query out of concatenated strings. Doing the latter exposes your application to SQL injection attacks.
If none of your dates are in range, then the SQL query will return NULL. Calling getInt() on column in a result set that is NULL will return 0, so you will get the result you want in that case anyway. If the previous value you got from a result set was SQL NULL, then calling result.wasNull() will return true, so if you really did need to handle that case separately, you could use that mechanism to do so.
You can do:
public static int dateRange(){
int value = 0;
// Use try-with-resources to make sure resources are released:
try (
Connection connection = DriverManager.getConnection("", "", "");
PreparedStatement stmt = connection.prepareStatement(
"SELECT SUM(cost) FROM Items WHERE expiration_date between ? and ?");
) {
stmt.setDate(1, Date.valueOf(Budget.datePicker1.getValue()));
stmt.setDate(2, Date.valueOf(Budget.datePicker2.getValue()));
ResultSet result = stmt.executeQuery();
result.next();
// Note that if there are no values in range, the SQL result will be NULL
// and getInt() will return 0 anyway.
value = result.getInt(1);
// however, if you need to explicitly check this and do something different
// if nothing is in range, do:
if (result.wasNull()) {
// nothing was in range...
}
} catch (SQLException e){
// this actually indicates something went wrong. Handle it properly.
Logger.getGlobal().log(Level.SEVERE, "Error accessing database", e);
// inform user there was a db error, etc...
}
return value;
}
I have a web API returning 117k JSON objects.
Edit: The API is calling MySQL to fetch 117k rows of data, putting them into a IEnumerable and sending them through JSON
All I see is
[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},... the entire page...
I wanted to ask how someone what is happening and how you would handle a large JSON transfer. Prefer to get it all in one go to avoid querying back and forth (delay time).
The function call is this:
public IEnumerable<Score> Get(int id)
{
string mConnectionString = System.Configuration.ConfigurationManager.AppSettings["mysqlConnectionString"];
MySqlConnection mConn;
MySqlDataReader mReader;
List<Score> returnedRows = new List<Score>();
if (String.IsNullOrEmpty(mConnectionString))
{
return returnedRows;
}
try
{
// prepare the dump query
MySqlCommand dumpCmd;
string query = "SELECT * FROM score where id = "+id+";";
using (mConn = new MySqlConnection(mConnectionString))
{
using (dumpCmd = new MySqlCommand())
{
dumpCmd.Connection = mConn;
dumpCmd.CommandText = query;
mConn.Open();
mReader = dumpCmd.ExecuteReader(); /
if (mReader.HasRows)
{
while (mReader.Read())
{
string[] rowCols = new string[mReader.FieldCount]; // there are 20+ columns, at least the primary keys are not null
for (int i = 0; i < rowCols.Length; ++i)
{
rowCols[i] = mReader.GetString(i);
}
returnedRows.Add(new Score(rowCols));
}
mConn.Close();
return returnedRows;
}
else
{
// should return a 404 cause nothing found
mConn.Close();
}
}
}
}
catch (Exception e)
{
return returnedRows;
}
return returnedRows;
}
Either mReader.GetString(i) is returning null or you have no data in the columns.
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.
Is there a way to directly display the content of a query in Mysql using C?
What I mean is:
through mysql shell if I type : SELECT * FROM table_name; I get the query result in a neat and formatted way.
If I want to do the same thing using Api C I have to write several lines of codes and the final result is far from being nice (at least this is my personal experience )
For example :
void display_Table1(MYSQL *conn)
{
int jj,ii;
char query[512];
sprintf(query, "SELECT * FROM Table1 ;");
if (mysql_query (conn, query)) {
printf("\nErrore query:\n");
printf("%s", mysql_error(conn),"\n");
result = mysql_store_result(conn);
if (result) {
num_rows = mysql_num_rows(result);
num_fields =mysql_num_fields(result);
//printf("Number of rows=%u Number of fields=%d \n", num_rows,num_fields);
//printf(" ");
}
else
{
printf("Result set is empty");
}
// Print column headers
fields = mysql_fetch_fields(result);
for(jj=0; jj < num_fields; jj++)
{
printf("\n%s\t\t",fields[jj].name);
}
printf("\n\t ");
// print query results
while(row = mysql_fetch_row(result)) // row pointer in the result set
{
for(ii=0; ii < num_fields; ii++)
{
printf("%s\t", row[ii] ? row[ii] : "NULL"); // Not NULL then print
}
printf("\n");
}
if(result)
{
mysql_free_result(result);
result = NULL;
}
}
}
That's a knotty problem to solve. I get headers one after the other in a vertical way.
I also get
Commands out of sync; you can't run this command now
Firstly, there is no direct way to print out a formatted display. What you can do, is use
MYSQL_FIELD *field = mysql_fetch_field (resultset);
col_len = field->max_length;
if(col_len < strlen(field->name))
col_len = strlen(field->name);
to find out the maximum width of a column, and the space the data accordingly.