I have a stored procedure call that goes like this:
using (OracleConnection con = new OracleConnection(ConfigurationManager.AppSettings["Database"]))
using (OracleCommand cmd = new OracleCommand("Package.Procedure", con))
{
Int32 existsCount;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("successCount", OracleDbType.Int32, 0, ParameterDirection.InputOutput);
cmd.Parameters.Add("BusinessId", OracleDbType.Int64, listRec.BusinessId, ParameterDirection.Input);
con.Open();
cmd.ExecuteScalar();
con.Close();
existsCount = Convert.ToInt32(cmd.Parameters["successCount"].Value);
return (existsCount);
}
But on this line:
existsCount = Convert.ToInt32(cmd.Parameters["successCount"].Value);
It throws the Exception "Unable to cast object of type 'Oracle.DataAccess.Types.OracleDecimal' to type 'System.IConvertible'."
Any thoughts? Thanks.
You can also try:
Oracle.DataAccess.Types.OracleDecimal d = (Oracle.DataAccess.Types.OracleDecimal)cmd.Parameters["successCount"].Value;
if( d.IsNull )
existsCount = 0;
else
existsCount = d.ToInt32( );
What about
existsCount = int.Parse(cmd.Parameters["successCount"].Value.ToString());
It is more efficient to use
Convert.ToInt32((decimal)(OracleDecimal)(cmd.Parameters["successCount"].Value))
I don't know the return type at runtime because the execution code is within a cross-platform data access framework under development, so I used a switch on the parameter value type to access the underlying Oracle[type].Value property for the various Oracle managed data access types.
public override object GetValue(IDataParameter parameter)
{
if (parameter == null)
{
throw new ArgumentNullException(nameof(parameter));
}
// https://docs.oracle.com/cd/B19306_01/win.102/b14307/OracleDbTypeEnumerationType.htm
if (parameter is OracleParameter)
{
switch (parameter.Value)
{
case OracleBinary oracleBinary:
// returns byte[]
return oracleBinary.Value;
case OracleBoolean oracleBoolean:
// returns bool
return oracleBoolean.Value;
case OracleDate oracleDate:
// returns DateTime
return oracleDate.Value;
case OracleDecimal oracleDecimal:
// oracleDecimal.Value is Decimal, so we convert to correct type.
return parameter.DbType == DbType.Decimal
? oracleDecimal.Value
: Convert.ChangeType(oracleDecimal.Value, parameter.DbType.ToType());
case OracleIntervalDS oracleIntervalDS:
// returns TimeSpan
return oracleIntervalDS.Value;
case OracleIntervalYM oracleIntervalYM:
// returns Long
return oracleIntervalYM.Value;
case OracleTimeStamp oracleTimeStamp:
// returns DateTime
return oracleTimeStamp.Value;
case OracleTimeStampLTZ oracleTimeStampLTZ:
// returns DateTime
return oracleTimeStampLTZ.Value;
case OracleTimeStampTZ oracleTimeStampTZ:
// returns DateTime
return oracleTimeStampTZ.Value;
default:
throw new NotSupportedException(
parameter.Value != null
? parameter.Value.GetType().Name
: parameter.ParameterName);
}
}
else
{
throw new NotSupportedException(parameter.GetType().Name);
}
}
In my case, I'm using Bulk Insert in Oracle, and meet the same error, let me share my solution here. I solved it by adding
oracleCommand.ArrayBindCount = datas.Count;
that is I forgot to set the ArrayBindCount property.
I suggest you convert to String, and after that you convert from String to Integer.
Dim tmpIdSesiónCalificación As String =
parametroIdSesiónCalificación.Value.ToString
_idSesiónCalificación = Convert.ToInt32(tmpIdSesiónCalificación)
Related
I have a question in relation to this one:
MySqlCommand call function
Using MariaDB
10.5.11-MariaDB-1:10.5.11+maria~focal
and the given function (simplified)
CREATE FUNCTION `activity_plugin_active`() RETURNS binary(1)
BEGIN
DECLARE result INT DEFAULT 0;
RETURN result;
END
To get the result in .NET of the function I use a helper method
bool activitiesPluginActive = 1 == ExecuteIntScalarAsync(
"activity_plugin_active",
null,
CancellationToken.None)
.GetAwaiter().GetResult();
But this method is a bit bulky
private async Task<int> ExecuteIntScalarAsync(
string functionName,
IEnumerable<DbParameter> parameters,
CancellationToken cancellationToken = default)
{
using (MySqlConnection conn = new MySqlConnection(databaseConfiguration.GetConnectionString()))
{
await conn.OpenAsync();
MySqlCommand cmd = new MySqlCommand(functionName)
{
CommandType = CommandType.StoredProcedure,
Connection = conn
};
if (parameters != null)
foreach (var parameter in parameters)
cmd.Parameters.Add(parameter);
var returnValue = new MySqlParameter("returnvalue", MySqlDbType.Int32)
{
Direction = ParameterDirection.ReturnValue
};
cmd.Parameters.Add(returnValue);
logger.LogInformation($"Executing { functionName }");
await cmd.ExecuteScalarAsync(cancellationToken);
// return value is byte[1], value 48
byte[] bytes = returnValue.Value as byte[];
// need to cast to string, value "0"
var sValue = System.Text.Encoding.Default.GetString(bytes);
// need to cast to int
return Convert.ToInt32(sValue);
}
}
As you see in the code comments above the return value is a byte[1] - with the given function it has the value 48 - ASCII CODE for number zero.
Although the return type is defined as MySqlDbType.Int32.
How do I get directly returned an integer without the need to cast twice?
It is because in your function you are specifying that return the result of function as binary(1) (i.e. RETURNS binary(1)) . Can you try changing it to INT like:
CREATE FUNCTION `activity_plugin_active`() RETURNS INT
BEGIN
DECLARE result INT DEFAULT 0;
RETURN result;
END
I have this method:
public void UpdatePhrase(PHRASE phraseColumn, bool value, string phraseId)
{
sql = string.Format("UPDATE Phrase SET " + phraseColumn.Text() + " = {0} WHERE PhraseId = '{1}'", value, phraseId);
App.DB.RunExecute(sql);
}
It's not working correctly as it seems like I need the value of {0} needs to be a 0 or a 1.
Is there a simple way that I can take value and change it to be a 0 or a 1?
Just do value ? 1 : 0, it's that easy!
#Sean has given to you the natural fix to your problem, but, in my view, what you really need to do here is to refactor your App.Db.RunExecute to receive parameters, so you can write
public void UpdatePhrase(PHRASE phraseColumn, bool value, string phraseId)
{
sql = "UPDATE Phrase SET " + phraseColumn.Text() + " = #v WHERE PhraseId = #id";
List<SqlParameter> prms = new List<SqlParameter>
{
new SqlParameter {ParameterName = "#v", SqlDbType = SqlDbType.Boolean, Value = value},
new SqlParameter {ParameterName = "#id", SqlDbType = SqlDbType.NVarChar, Value = phraseId}
};
App.DB.RunExecute(sql, prms);
}
This will partially remove the Sql Injection problem (I say partially because that phraseColumn.Text() is still source of concerns if its value comes from the user input)
Now RunExecute should change to
void RunExecute(string sqlCommand, List<SqlParameter> prms = null)
{
// usual code to open connection and create a command
......
// If the caller passes a parameters list, add them to the command
if(prms != null)
cmd.Parameters.AddRange(prms.ToArray());
// Now execute the command
cmd.ExecuteNonQuery();
}
The change to RunExecute uses an optional argument, so your current code is not affected by the presence of the new argument but you will be able to write better Sql code from now on.
value ? 1 : 0
as in #Sean answer or
Convert.ToInt32(value)
ToInt32(Boolean) Converts the specified Boolean value to the
equivalent 32-bit signed integer.
You can use the int count = updateCommand.ExecuteNonQuery; so if count>0, it means our mission is done 1 (True) , otherwise 0 (False)
updateCommand.Parameters.AddWithValue("#Var" , "Johne");
try
{
connection.Open();
int count = updateCommand.ExecuteNonQuery;
if (count > 0)
return true;
else
return false;
}
catch (SqlException ex)
{
throw ex;
}
finally
{
connection.Close();
}
}
I hope you got the point ^_^.
you can do (GetHashCode on booleans returns a constant 1/0, no calculation):
true.GetHashCode() // 1
false.GetHashCode() // 0
public object VerySimplyCompactFastTrueBestConvertObjectToInt(object whatNeedToConvertBro, object whatTypeIsYoNeedBro)
{
var typeOfConvertingObject = whatNeedToConvertBro.GetType();
var objWhatWillBeaReturnedInOut = new object();
if ((typeOfConvertingObject == whatTypeIsYoNeedBro.GetType()) == true)
{
objWhatWillBeaReturnedInOut = Convert.GetTypeCode(whatTypeIsYoNeedBro);
}
return objWhatWillBeaReturnedInOut;
}
}
public void UpdatePhrase(PHRASE phraseColumn, bool value, string phraseId)
{
sql = string.Format("UPDATE Phrase SET {phraseColumn} = {value ? 1 : 0} WHERE PhraseId = '{phraseId}'");
App.DB.RunExecute(sql);
}
But that can be subject to SQL injection attacks, so better to write it as a parameterised query.
For scenarios needing extreme performance, you can use the System.Runtime.CompilerServices.Unsafe package to perform this conversion directly inline. This will result in native code that contains no branching or function calls.
using System.Runtime.CompilerServices;
/// ...
bool _bool;
byte _byte;
_bool = true;
_byte = Unsafe.As<bool, byte>(ref _bool);
Console.WriteLine(_byte); // --> 1
_bool = false;
_byte = Unsafe.As<bool, byte>(ref _bool);
Console.WriteLine(_byte); // --> 0
You can also use this method to set up a ref local byte variable which existentially represents the instantaneous identity of the Boolean, but viewed as a byte. This might be useful for persistently monitoring a changing { false, true } using a { 0, 1 } interpretation.
class Program
{
static bool _bool;
static void Main()
{
Task.Factory.StartNew(() => { while (true) _bool = !_bool; });
// define a "ref local" that persistently views Boolean value '_bool' as a byte
ref byte _byte = ref Unsafe.As<bool, byte>(ref _bool);
while (true)
Console.Write(_byte + " ");
}
};
If you're unfamiliar with ref, with this technique just shown there is no "machinery" involved in any sort of "updating" or "conversion" whenever the value changes, because the ref byte is actually just a different "view" of the original Boolean entity itself.
The output is somewhat mesmerizing.
I'm trying to do an AppendLine with this
reportLayout.AppendLine(
"Sold Items".PadRight(25) +
Convert.ToString(BatchCalculation.NoOfItems(dBCommand, transDate, reportType)));
And I'm getting an exception thrown
Specified Cast is not valid
my NoOfItems is a static method and it returns an int
EDIT: Last lines of code in NoOfItems method
...
using (DbDataReader reader = dBCommand.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
//hsBatch.currentTC = (int)reader["CURRENTTC"];
//hsBatch.currentAmt = (decimal)reader["CURRENTPYMTAMT"];
//Cancellation fee
hsBatch.TotalNoOfitems = (int)reader["TOTALNOOFITEMS"];
}
}
}
}
}
finally
{
if (connection.State == ConnectionState.Open)
connection.Close();
}
return hsBatch.TotalNoOfitems;
}
Database can return null, so I would suggest to check DBNull
hsBatch.TotalNoOfitems = reader["TOTALNOOFITEMS"] != DBNull.Value ? int.Parse(reader["TOTALNOOFITEMS"].ToString()):0;
It seems you have a problem with type mapping (RDBMS Number is not necessary .Net int):
// (int) - cast like this may well be incorrect:
// reader["TOTALNOOFITEMS"] is not nesseary int or can be cast to int
hsBatch.TotalNoOfitems = (int)reader["TOTALNOOFITEMS"];
Instead of
if (reader.HasRows)
{
while (reader.Read())
{
//hsBatch.currentTC = (int)reader["CURRENTTC"];
//hsBatch.currentAmt = (decimal)reader["CURRENTPYMTAMT"];
//Cancellation fee
hsBatch.TotalNoOfitems = (int)reader["TOTALNOOFITEMS"];
}
}
Put
// if: we don't want "while" since we read one record only
// reader.HasRows is redundant - if we manage to read a record we have it
if (reader.Read())
{
// hsBatch.currentTC = Convert.ToInt32(reader["CURRENTTC"]);
// hsBatch.currentAmt = Convert.ToDecimal(reader["CURRENTPYMTAMT"]);
// What ever RDBMS type mapping is (byte, short, int, long, decimal
// or even string - depending on query, RDBMS and settings)
// try convert it into int - Int32
hsBatch.TotalNoOfitems = Convert.ToInt32(reader["TOTALNOOFITEMS"]);
}
There's one more (possible) issue: if TOTALNOOFITEMS field contains NULL value. If it's your case, you can put
hsBatch.TotalNoOfitems = reader["TOTALNOOFITEMS"] == DBNull.Value
? 0 // or whatever value in case of null
: Convert.ToInt32(reader["TOTALNOOFITEMS"]);
I have a class with the following code
public cCase(string pCaseNo, string pMode)
{
if (pMode == "new")
{
this._caseNo = Validate_CaseNo(pCaseNo);
}
if (pMode == "existing")
{
try
{
int intValidatedCaseNo = Validate_CaseNo(pCaseNo);
string sqlText = "SELECT * FROM tblCases WHERE CaseNo = #CaseNo;";
string strConnection = cConnectionString.BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(sqlText, linkToDB);
sqlCom.Parameters.Add("#CaseNo", SqlDbType.Int);
sqlCom.Parameters["#CaseNo"].Value = intValidatedCaseNo;
SqlDataReader caseReader = sqlCom.ExecuteReader();
if (caseReader.HasRows)
while (caseReader.Read())
{
this._claimant = caseReader["Claimant"].ToString();
this._defendant = caseReader["Defendant"].ToString();
this._caseType = caseReader["CaseType"].ToString();
this._occupation = caseReader["Occupation"].ToString();
this._doa = (DateTime?)caseReader["DOA"];
this._dateClosed = (DateTime?)caseReader["DateClosed"];
this._dateSettled = (DateTime?)caseReader["DateSettled"];
this._dateInstructed = (DateTime?)caseReader["DateInstructed"];
this._status = caseReader["Status"].ToString();
this._instructionType = caseReader["InstructionType"].ToString();
this._feeEstimate = (decimal?)caseReader["FeeEstimate"];
this._amountClaimed = (decimal?)caseReader["AmountClaimed"];
this._amountSettled = (decimal?)caseReader["AmountSettled"];
this._caseManager = caseReader["CaseManager"].ToString();
}
caseReader.Close();
linkToDB.Close();
linkToDB.Dispose();
}
catch (Exception eX)
{
throw new Exception("Error finding case" + Environment.NewLine + eX.Message);
}
}
}
However the Datetime? casts fail with an 'Invalid Cast'.
I've checked the SQL database and the field is storing valid dates
So I cant work out why, as I extract info via the DataReader into my app, the datetime fields are causing an Invalid Cast.
Please help.
You're going to want to change the line that reads:
this._doa = (DateTime?)caseReader["DOA"];
to:
if (caseReader["DOA"] != DBNull.Value)
this._doa.Value = (DateTime)caseReader["DOA"];
As well as all similar lines.
DBNull values cannot be casted from Nullable types.
Your DateTime fields probably hold a DBNull value which you cannot convert directly.
However, I'd use an extension method on your DataReader for convinience.
public static class DataReaderExtensions
{
public static DateTime? ReadNullableDateTime(this IDataReader reader, string column)
{
return reader.IsDBNull(column) ? (DateTime?)null : reader.GetDateTime(column);
}
}
// Usage
this._dateInstructed = CaseReader.ReadNullableDateTime("DateInstructed");
You should use
DateTime.TryParse Method
this not throw exception, like
var mydate =(DateTime)datetimeString
or
var mydate =DateTime.Parse(datetimeString)
does!!!
Try with the following code part
this._doa = (caseReader["DOA"] == DBNull.Value ? DBNull.Value : Convert.ToDateTime(caseReader["DOA"]);
Try to Convert Date Time as
this._doa = Convert.ToDateTime(caseReader["DOA"]);
I often deal with DBNull.Value...
So I use this method that will return the value of the object or the default value of the given value type if object's value is DBNull.Value.
public static object GetValueOrDefault(object value, Type type)
{
if (value != DBNull.Value)
return value;
if (type.IsValueType == false)
return null;
Array array = Array.CreateInstance(type, 1);
return array.GetValue(0);
}
Usage:
GetValueOrDefault(dataRecord.GetValue(fieldIndex), dataRecord.GetFieldType(fieldIndex)
I am calling a function as:
string judge1 = abs.getjud1(this.HiddenField4, this.TextBox3);
The function being called is:
public string getjud1(HiddenField HiddenField4, TextBox TextBox3)
{
String dbDate = DateTime.ParseExact(TextBox3.Text, "dd/mm/yyyy", null).ToString("yyyy-mm-dd");
try
{
OdbcConnection casetype = new OdbcConnection("Driver={MySQL ODBC 3.51 Driver};Server=10.155.160.130;Database=testcase;User=root;Password=;Option=3;");
casetype.Open();
//*********to get jud1
string jud1query = "select jname from testcase.orddetpabak,testcase.judge where orddetpabak.jud1 = judge.jcode and fil_no=? and orderdate=?;";
//*********to get jud1
OdbcCommand jud1cmd = new OdbcCommand(jud1query, casetype);
jud1cmd.Parameters.AddWithValue("?", HiddenField4.Value);
jud1cmd.Parameters.AddWithValue("?", dbDate);
using (OdbcDataReader jud1MyReader = jud1cmd.ExecuteReader())
{
while (jud1MyReader.Read())
{
judge1 = jud1MyReader["jname"].ToString();
Globals.jjj1= "J";
}
}
}
catch (Exception ep)
{ }
return judge1;
}
I want to return judge1 and Globals.jjj1, is it possible to do that? If so than how to do it?
Return a Tuple
http://msdn.microsoft.com/en-us/library/system.tuple.aspx
Not quite sure what you mean, but if you want to return multiple values, you can use the out or ref keywords.
Out keyword
Ref keyword
void SomeFunction()
{
int value1;
int value2;
value1 = SomeOtherFunction(out value2);
//Value1 now equals 21, value2 equals 25.
//You can use the same thing for strings.
}
int SomeOtherFunction(out int value2)
{
value2 = 25;
return 21;
}
Create an object with the 2 string values that represent the values you want and then return the object.
public MyCustomObject getjud1(HiddenField HiddenField4, TextBox TextBox3)
You can only return one object from your method, but you have two options here:
Make a new object that contains two strings, and return this object from the method instead of the string. This way, your composite object will contain the values you want.
Make a new parameter that you mark as out, and set the value of that parameter inside the method. The variable you send into the method as a parameter will then be updated outside the method as well.
Since C# is an object oriented language, why not simply make an object that contains all the values that you want to return? That way you only have one variable for your return statement, but you have access to all the values that you require.