The code issue is in a WinCE application written in VS2008 using CoreLab with an Oracle SQL backend. The details are as follows :
A 20 digit number is added to a parameter list to be used in the execution of a procedure. If the number ends in 00 the printout from the procedure indicates that the value never reached the procedure, though it works correctly in other cases.
Below is the code which adds the parameters and executes the procedure :
public static List<OracleParameter> ExecProc(string proc, List<OracleParameter> parameters, OracleConnection conn)
{
if (conn == null)
{
throw new Exception("Unable to connect");
}
if (proc == null || proc == "")
{
throw new Exception("Procedure name cannot be blank");
}
CheckConnState(conn);
List<OracleParameter> paramOutList = new List<OracleParameter>();
OracleCommand com = new OracleCommand();
com.Connection = conn;
OracleTransaction trans = conn.BeginTransaction();
com.CommandTimeout = 0;
com.CommandText = proc;
com.CommandType = CommandType.StoredProcedure;
foreach (OracleParameter param in parameters)
{
com.Parameters.Add(param.ParameterName, param.OracleDbType).Value = param.Value;
com.Parameters[param.ParameterName].Direction = param.Direction;
if (param.Direction == ParameterDirection.Output)
{
paramOutList.Add(com.Parameters[param.ParameterName]);
}
}
try
{
com.ExecuteNonQuery();
//Set the output parameter values for use outside
if (paramOutList.Count > 0)
{
foreach (OracleParameter p in paramOutList)
{
p.Value = com.Parameters[p.ParameterName].Value;
//Check if there are errors and either rollback or commit. We can't leave the transaction open
if (p.ParameterName.IndexOf("error") > 0)
{
if (p.Value.ToString() != null && p.Value.ToString() != "")
{
trans.Rollback();
}
else
{
trans.Commit();
}
}
}
}
else
{
trans.Commit();
}
return paramOutList;
}
catch
{
trans.Rollback();
return paramOutList;
}
}
Edit :
Below is the sample code which calls the aforementioned method.
List<OracleParameter> paramList = new List<OracleParameter>
{
GenericLib.AddParam("pn_id", OracleDbType.Number, iLongId),
GenericLib.AddParam("pn_indicator", OracleDbType.Number, iInd),
GenericLib.AddParam("pn_user_id", OracleDbType.Number, iUserId),
GenericLib.AddParam("pv_in_code", OracleDbType.VarChar, null, ParameterDirection.Output),
GenericLib.AddParam("pv_out_code", OracleDbType.VarChar, null, ParameterDirection.Output),
GenericLib.AddParam("pv_error_code", OracleDbType.VarChar, null, ParameterDirection.Output)
};
List<OracleParameter> output = GenericLib.ExecProc("sample_procedure", paramList, conn);
From what I can see the first parameter never reaches the database layer as I did a printout on the first line in the proc.
Related
I must connect one database present in HeidiSql to my .Net project in visual studio. When i debug my project while i am doing connection with db i obtain the error in the field Server Version with the description '.server Version has generated an exception of type System.InvalidOperationException '. Do you know what is the reason?
My connection string is :
<connectionStrings>
<add name="TicketDB"
connectionString="server=localhost;user id=root;password=Omega;database=crm6"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
The code is:
public void getNumberAllTicketOpen()
{
try
{
clDataBase ticketDB = new clDataBase();
string sQuery = "SELECT * from ticket";
DataTable ticket = ticketDB.ExecuteDataTable(sQuery, null, false);
Console.WriteLine("i am here!");
}
catch (Exception e)
{
Console.WriteLine("Errore : " + e.Message);
}
finally
{
}
}
public DataTable ExecuteDataTable(string CommandText, List<SqlParameter> Params = null, bool isStoredProcedure = true)
{
SqlConnection oCnn = null;
SqlCommand oCmd = null;
SqlDataAdapter oAdap = null;
try
{
**oCnn = new SqlConnection(this.connectionString);
oCnn.Open();** //this is the line that launch the error
oCmd = new SqlCommand(CommandText, oCnn);
if (isStoredProcedure)
oCmd.CommandType = System.Data.CommandType.StoredProcedure;
else
oCmd.CommandType = System.Data.CommandType.Text;
oCmd.CommandTimeout = this.commandTimeOut;
if (Params != null)
{
foreach (SqlParameter p in Params)
oCmd.Parameters.Add(p);
}
oAdap = new SqlDataAdapter(oCmd);
DataTable ResultTable = new DataTable();
oAdap.Fill(ResultTable);
return ResultTable;
}
catch (Exception ex)
{
logger.Error("Errore esecuzione " + CommandText, ex, MethodInfo.GetCurrentMethod().Name + " in " + MethodInfo.GetCurrentMethod().Module.Assembly.FullName);
throw;
}
}
oCnn = new SqlConnection(this.connectionString);
oCnn.Open(); //this is the line with error
Thank you for your help!
The error you are showing is an error encountered by the Visual Studio debugger attempting to view a property of a SqlConnection object.
The property in question is ServerVersion. I'm guessing the connection would only know what version of MySQL is running on the server when it actually manages to connect to the server, but at the point you've stopped the code, it hasn't connected yet. It doesn't make sense to return the server version at that point, so throwing an InvalidOperationException is an appropriate response.
I see exceptions like this in the VS debugger quite often. They are nothing to worry about. Not every property on every object is valid all the time.
I have resolved my problem.
I was trying to connect to a mySQL database but there were error in my code. I have resolved with the installation of the package MySql.Data with NuGet and the replacement in the code of SqlConnection, SqlCommand, SqlDataAdapter respectively with MysqlConnection, MySqlCommand, MySqlDataAdapter. Below i write the modified code:
public DataTable ExecuteDataTable(string CommandText, List<MySqlParameter> Params = null, bool isStoredProcedure = true)
{
MySqlConnection oCnn = null;
MySqlCommand oCmd = null;
MySqlDataAdapter oAdap = null;
try
{
oCnn = new MySqlConnection(this.connectionString);
oCnn.Open();
oCmd = new MySqlCommand(CommandText, oCnn);
if (isStoredProcedure)
oCmd.CommandType = System.Data.CommandType.StoredProcedure;
else
oCmd.CommandType = System.Data.CommandType.Text;
oCmd.CommandTimeout = this.commandTimeOut;
if (Params != null)
{
foreach (MySqlParameter p in Params)
oCmd.Parameters.Add(p);
}
oAdap = new MySqlDataAdapter(oCmd);
DataTable ResultTable = new DataTable();
oAdap.Fill(ResultTable);
return ResultTable;
}
catch (Exception ex)
{
logger.Error("Errore esecuzione " + CommandText, ex, MethodInfo.GetCurrentMethod().Name + " in " + MethodInfo.GetCurrentMethod().Module.Assembly.FullName);
throw;
}
finally
{
if (oCnn != null)
{
if (oCnn.State != System.Data.ConnectionState.Closed)
oCnn.Close();
oCnn.Dispose();
}
if (oAdap != null)
oAdap.Dispose();
if (oCmd != null)
oCmd.Dispose();
if (Params != null)
{
Params.Clear();
Params = null;
}
}
I am trying to call a stored procedure which has an INT parameter (BusinessID) and allows NULL. From my C# code, I can't figure out if data is null, how to identify and pass. I have listed three techniques I have tried numbered #1,#2,#3 and the errors I get. Please guide
Here is my sample code:
private static DataRow ValidateRecord (string ProjectNum, int? BusinessID)
{
DataRow returnRow = null;
using (SqlConnection connection = Connection.GetConnection())
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
try
{
using (SqlCommand command = new SqlCommand(
"[dbo].[mySQLProc]", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 90;
command.Parameters.Add("#ProjectNum", SqlDbType.VarChar, 17).Value = ProjectNum;
// #1 – error: "Data is Null. This method or property cannot be called on Null values."
//if (!BusinessID.HasValue)
//{
// BusinessID = (int)System.Data.SqlTypes.SqlInt32.Null;
//}
//#2 - "Data is Null. This method or property cannot be called on Null values."
if (BusinessID == null)
{
BusinessID = (int)System.Data.SqlTypes.SqlInt32.Null;
}
//#3 - error on compile time – Type of conditional expression cannot be determined because
// there is no implicit converstion between ‘System.DBNull’ and ‘int?’
// BusinessID = BusinessID == null ? DBNull.Value : BusinessID;
command.Parameters.Add("#BusinessID", SqlDbType.Int).Value = BusinessID;
command.ExecuteNonQuery();
connection.Close();
returnRow = CreateDataRow(ProjectNum, BusinessID);
}
}
catch (Exception ex)
{
throw ex;
}
return returnRow;
}
}
I have a DAL function that needs to call a stored procedure and get the dataset, along with a couple of OUT parameters. I can get the resulting dataset but not sure how to get the parameters.
Normally, the parameters are available through cmd.Parameters["ParamName"].Value but I am using another API to make the DB connection and return the resulting dataset, not sure how to get the OUT parameters in addition to dataset.
Here is what i have, so far:
Public static int getSomething(string inParam, out DataTable dtOut, out string outParam1, out string outParam2)
{
OracleDbCntext dbContext = new OracleDbContext();
DataSet dsOut = new DataSet()
DataTable dtOut = new dataTable();
....
try
{
List<OracleParameter> spParams = new List<OracleParameter>();
spParams.Add(new OracleParameter("INPARAM", OracleDbType.Varchar2, receptacleID, ParameterDirection.Input));
spParams.Add(new OracleParameter("OUTARAM1", OracleDbType.TimeStamp, null, ParameterDirection.Output));
spParams.Add(new OracleParameter("OUTARAM2", OracleDbType.TimeStamp, null, ParameterDirection.Output));
spParams.Add(new OracleParameter("CUR_OUT", OracleDbType.RefCursor, ParameterDirection.Output));
try
{
dbContext.Open();
dbContext.ExecuteStoredProcedure("SOME_PKG.USP_SOMESP", spParams, ref dsOutcome);
}
catch (Exception oConnException)
{
}
if (dsOut != null)
{
if (dsOut.Tables[0].Rows.Count > 0)
{
dtOut = dsOut.Tables[0];
//outParam1 = ????
//outParam2 = ????
}
}
}
}
namespace Something.Model.DataAccess
{
public class OracleDbContext
{
public OracleConnection DbConnection { get; private set; }
public OracleDbContext()
{
string ConnectionString = ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ConnectionString;
DbConnection = new OracleConnection(ConnectionString);
}
public void Open()
{
if (DbConnection.State != ConnectionState.Open)
{
DbConnection.Close();
DbConnection.Open();
}
}
public void Close()
{
if (DbConnection.State == ConnectionState.Open || DbConnection.State == ConnectionState.Broken)
{
DbConnection.Close();
DbConnection.Dispose();
}
}
public void ExecuteStoredProcedure(string spName, List<OracleParameter> spParams, ref DataSet dataset)
{
OracleDataAdapter da = null;
OracleTransaction oraTransaction = null;
using (OracleCommand command = new OracleCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(spParams.ToArray<OracleParameter>());
command.Connection = DbConnection;
command.CommandText = spName;
try
{
oraTransaction = DbConnection.BeginTransaction();
da = new OracleDataAdapter(command);
da.Fill(dataset);
oraTransaction.Commit();
}
catch (Exception e)
{
oraTransaction.Rollback();
}
finally
{
if (oraTransaction != null)
oraTransaction.Dispose();
if (DbConnection != null)
{
this.Close();
}
}
}
}
Stored Procedure in SOME_PKG:
PROCEDURE USP_SOMESP
(
INPARAM VARCHAR2,
OUTPARAM1 OUT TIMESTAMP,
OUTPARAM2 OUT TIMESTAMP,
CUR_OUT OUT GETDATACURSOR
)
....
LVSQUERY:='SELECT FIELD1, '''|| V_EVENTCODE ||''' AS EVENTCODE, ...
WHERE SOMETHING= '''|| V_LOC1||''' ';
OPEN CUR_OUT FOR LVSQUERY;
EXCEPTION WHEN OTHERS THEN
...;
END USP_SOMESP;
As you have a layer in the middle you might need to change your code a little bit.
Change this
spParams.Add(new OracleParameter("OUTARAM1", OracleDbType.TimeStamp, null, ParameterDirection.Output));
with
var outParam1 = new OracleParameter("OUTARAM1", OracleDbType.TimeStamp, null, ParameterDirection.Output);
spParams.Add(outParam1);
And then use the Value property:
outParam1.Value;
According to the documentation:
For output parameters the value is:
Set on completion of the OracleCommand (true for return value parameters also).
Set to the data from the database, to the data type specified in OracleDbType or DbType.
I'm trying to return a string value from my database but instead the query is returning "0" although the SELECT query is targeting a nvarchar column.
The query is valid and runs correctly, returning "KYO" when run using SQL-SMS.
This is the method, which works as expected in the other place I use it, that I use for returning data:
public static object GetData(string sql, SqlParameter[] parameters)
{
try
{
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = sql;
if (parameters != null)
{
foreach (var parameter in parameters)
{
if (parameter != null)
command.Parameters.Add(parameter);
}
}
object result = null;
SqlParameter returnValue = new SqlParameter("ReturnValue", result);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
connection.Open();
command.ExecuteScalar();
result = command.Parameters["ReturnValue"].Value;
return result;
}
}
}
catch (Exception)
{
throw;
}
}
}
This is the method which is throwing a cast exception as it's returning an int instead of a string:
private static String GetManufacturerCode(Int32 manufacturerID)
{
try
{
StringBuilder sql = new StringBuilder();
sql.Append("SELECT ManufacturerCode FROM Manufacturers WHERE ManufacturerID = #ID");
SqlParameter id = new SqlParameter("#ID", manufacturerID);
return(String)DB.GetData(sql.ToString(), new[] { id });
}
catch (Exception)
{
throw;
}
}
I also set returnValue.DbType = DbType.String; as a test and this still returned an integer.
An example of where I use the GetData(...) method successfully is:
public static Int32 GetMonitoredCount()
{
try
{
String GetMonitoredCount = "SELECT COUNT(*) FROM Devices WHERE Monitored = 1 ";
return (Int32)DB.GetData(GetMonitoredCount, null);
}
catch (Exception)
{
throw;
}
}
I considered it might be returning a boolean bit but as my query executes correctly I'd have assumed it would return 1 not 0.
Why is an integer being returned? How can I return a string using my pattern?
ReturnValue always returns int - this is by design.
Instead of this entire block
object result = null;
SqlParameter returnValue = new SqlParameter("ReturnValue", result);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
connection.Open();
command.ExecuteScalar();
result = command.Parameters["ReturnValue"].Value;
Try
connection.Open();
object result = command.ExecuteScalar();
This will return you real result of your SQL statement
Method ExecuteScalar itself is capable of returning value - it return first column of the first row of the resultset and is ideal when your query returns a single value.
I am passing table valued parameter to StoredProcedure.
Please check my code below
CREATE TYPE TempTable AS TABLE
(A nvarchar(50), B nvarchar(50), C nvarchar(500))
SqlParameter[] param = new SqlParameter[3];
param[0] = new SqlParameter("#A", A);
param[1] = new SqlParameter("#B", B);
param[2] = new SqlParameter("#C", lstC);
param[2].SqlDbType = SqlDbType.Structured;
param[2].TypeName = "dbo.TempTable ";
DataSet ds = SqlHelper.ExecuteDataset("StoredProcedureName", param);
Here , lstC is List object of class.
But getting error "Failed to convert parameter value from a List1 to a IEnumerable1."
EDIT
public static DataSet ExecuteDataset(string spName, params object[] parameterValues)
{
if (connectionString == null || connectionString.Length == 0) throw new ArgumentNullException("connectionString");
if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");
// If we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
// Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
// Assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
// Call the overload that takes an array of SqlParameters
return ExecuteDataset(CommandType.StoredProcedure, spName, commandParameters);
}
else
{
// Otherwise we can just call the SP without params
return ExecuteDataset(CommandType.StoredProcedure, spName);
}
}
public static DataSet ExecuteDataset(CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
if (connectionString == null || connectionString.Length == 0) throw new ArgumentNullException("connectionString");
// Create & open a SqlConnection, and dispose of it after we are done
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// Call the overload that takes a connection in place of the connection string
return ExecuteDataset(connection, commandType, commandText, commandParameters);
}
}
public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, String commandText, params SqlParameter[] commandParameters)
{
if (connection == null) throw new ArgumentNullException("connection");
// Create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
bool mustCloseConnection = false;
PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection);
// Create the DataAdapter & DataSet
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
DataSet ds = new DataSet();
cmd.CommandTimeout = 0;
// Fill the DataSet using default values for DataTable names, etc
da.Fill(ds);
// Detach the SqlParameters from the command object, so they can be used again
cmd.Parameters.Clear();
if (mustCloseConnection)
connection.Close();
// Return the dataset
return ds;
}
}
PREPARE COMMAND
private static void PrepareCommand(SqlCommand command, SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, out bool mustCloseConnection)
{
if (command == null) throw new ArgumentNullException("command");
if (commandText == null || commandText.Length == 0) throw new ArgumentNullException("commandText");
// If the provided connection is not open, we will open it
if (connection.State != ConnectionState.Open)
{
mustCloseConnection = true;
connection.Open();
}
else
{
mustCloseConnection = false;
}
// Associate the connection with the command
command.Connection = connection;
// Set the command text (stored procedure name or SQL statement)
command.CommandText = commandText;
// If we were provided a transaction, assign it
if (transaction != null)
{
if (transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
command.Transaction = transaction;
}
// Set the command type
command.CommandType = commandType;
// Attach the command parameters if they are provided
if (commandParameters != null)
{
AttachParameters(command, commandParameters);
}
return;
}
Came here during a project update to .Net Core 3.1 and started getting this error on previously-working code. This might only help you if you are going to Core 3.1+
Turns out it was a problem with the type of SqlDataRecord I was using when creating the structured data to send to my sproc.
old: Microsoft.SqlServer.Server.SqlDataRecord
new: Microsoft.Data.SqlClient.Server.SqlDataRecord
Note I had also moved from System.Data.SqlClient to Microsoft.Data.SqlClient based on their advice for .Net Core 3.1 and beyond and to clear up another error prior to finding the one that started this post.
If you're passing table data via a parameter, you need to use a User Defined Table Type, e.g.:
CREATE TYPE [dbo].[TempTable] AS TABLE(
[A] [varchar](50) NULL,
[B] [varchar](50) NULL,
[C] [varchar](500) NULL,
)
And lstC should be a DataTable or IEnumerable<SqlDataRecord> and not simply a list of your own class.
Try:
param[2] = new SqlParameter("#C", lstC.Select(c => c.ToSqlDataRecord()));
Where ToSqlDataRecord is a helper function in your class. Example:
public class Thing {
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
// to match the dbo.TempTable User-Defined Table Type on database
private static readonly SqlMetaData[] myRecordSchema = {
new SqlMetaData("A", SqlDbType.VarChar, 50),
new SqlMetaData("B", SqlDbType.VarChar, 50),
new SqlMetaData("C", SqlDbType.VarChar, 500)
};
public SqlDataRecord ToSqlDataRecord() {
var record = new SqlDataRecord(myRecordSchema);
record.SetString(0, A);
record.SetDateTime(1, B);
record.SetDateTime(2, C);
return record;
}
}