I have a method that calls a Stored Procedure in MySQL database:
public DataTable ExecuteSP_ReturnDataTable(DynamicGridAction pAction)
{
DataTable ret = new DataTable();
MySqlCommand wCmd = new MySqlCommand();
try
{
wCmd = new MySqlCommand(pAction.SPName);
wCmd.CommandType = CommandType.StoredProcedure;
wCmd.Parameters.Add(new MySqlParameter(pAction.SPParameterName, MySqlDbType.LongText)).Value = pAction.SPParameterViewColumn;
MySqlParameter outMessage = new MySqlParameter("pmessage", MySqlDbType.LongText);
outMessage.Direction = ParameterDirection.Output;
wCmd.Parameters.Add(outMessage);
if (base.mSqlTransaction == null)
wCmd.Connection = base.GetOpenedConection();
else
{
wCmd.Connection = (MySqlConnection)base.mSqlTransaction.Connection;
wCmd.Transaction = (MySqlTransaction)base.mSqlTransaction;
}
ret.Load(wCmd.ExecuteReader());
return ret;
}
catch (MySqlException exp)
{
throw new FunctionalException(exp.Number, exp);
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (base.mSqlTransaction == null)
base.CloseConection();
}
}
The StoredProcedure name and Parameter name are dinamics.
When I execute that method at the first time, it works. After that, I changed the name of the storedprocedure parameter in mysql (newParamName), and I change the "pAction.SPParameterName" value with the same (newParamName).
I execute that method after that and, surprisingly, the wCmd.ExecuteReader() method throws me:
System.ArgumentException: 'Parameter 'oldParamName' not found in the collection.'
I debug the code step by step and the name of the parameter is correct (the new one), but i get that exception every time I call that method.
But, if I restart the application (.net6 webapi), it works.
I think that there is some kind of "cache" for the StoredProcedure definition in my aplication.
The problem is that I need to change the parameter's name (I took it from other table in database), but the method continue internally calling the old one until I restart the aplication.
If you're using MySql.Data, set Procedure Cache Size = 0; in your connection string.
From Connection Options Reference:
ProcedureCacheSize, Procedure Cache Size, procedure cache, procedurecache
Default: 25
Sets the size of the stored procedure cache. By default, Connector/NET stores the metadata (input/output data types) about the last 25 stored procedures used. To disable the stored procedure cache, set the value to zero (0).
Related
Does anyone know of a way to call an Oracle 19 stored procedure in C# without the command object requiring an implicit Ref Cursor be created?
I have no need for any output from this procedure.
It just deletes records that are more than 2 hours old from a table - maybe there's some there - maybe not. There never is any output that I need back from this procedure.
When I try to execute it:
OraCommand.CommandText = sql;
OraCommand.CommandType = CommandType.StoredProcedure;
for (var i = 0; i < args.Length; i += 2)
{
OraCommand.Parameters.Add(args[i], OracleDbType.Varchar2).Value = args[i+1];
}
try
{
OraConn.Open();
}
catch (Exception ex)
{
return ex.Message;
}
int RowsAffected = OraCommand.ExecuteNonQuery();
I get this error:
Operation is not valid due to the current state of the object.
The command object contains this error:
OraCommand.ImplicitRefCursors' threw an exception of type 'System.NullReferenceException'
Does anybody know why?
Thanks
I have a class function where I'm trying to read data from a database table using the SqlDataReader. When the SqlCmd.ExecuteReader() is called, I see(upon debugging) that the resultView of the SqlDataReader says "Enumeration yielded no results". However, the SqlDataReader.Read() still returns true and therefore enters the while() code block.
The query executes correctly on SQL, and even changing the query to get data from other tables give the same results. Please note that I have several other functions in a separate class executing the similar code to get data from these same database tables and they work without any issue.
Another observation is that after the ExecuteReader() is called, the VisibleFieldCount field of the SQLDataReader has the value = 11, which is equal to the total number of columns in the Customer table. This suggests that the reader is able read atleast some of the data from the database.
Any suggestions or help will be appreciated. Please let me know if any more information is required.
I have tried simplifying the function code as much as possible by removing any code logic other than the data retrieval part for the ease of debugging.
public bool MatchPassword(string username, string enteredPassword)
{
bool loginSuccessful = false;
string returnedpasswordbinary;
DatabaseConnection databaseConnectionObj = new DatabaseConnection();
databaseConnectionObj.CreateDBConnection(); //Sets the connection string and opens database connection
string query = "SELECT * FROM dbo.Customers WHERE CustomerID='ALFKI';";
SqlCommand sqlCommandObj = new SqlCommand();
sqlCommandObj.CommandText = query;
sqlCommandObj.Connection = databaseConnectionObj.SqlConnectionObj1;
try
{
SqlDataReader sqlDataReaderObj = sqlCommandObj.ExecuteReader();
if (sqlDataReaderObj.HasRows)
{
while (sqlDataReaderObj.Read())
{
returnedPasswordBinary = sqlDataReaderObj[0].ToString();
}
}
}
catch (Exception ex)
{
throw ex;
}
return loginSuccessful;
}
Can you please set commandtype
command.CommandType = CommandType.Text;
I've got an ASP.NET MVC site with an admin page where I need to merge two records. I'm passing in two values, #old and #new. After adding those to my SqlCommand object, I call the ExecuteNonQuery(). This is generating an exception with the message saying
stored procedure 'FixDuplicate' expects parameter '#old' which was
not supplied
As you can see below, I'm definitely adding the parameter. All 3 versions that I've tried are there.
What's wrong with this code?
Version 1: (please ignore the syntax of this one, I already removed this code, but I did try it and confirmed that the parameters existed when it reached the ExecuteNonQuery() call)
var sql = "FixDuplicate";
comm.Parameters.Add(new System.Data.SqlClient.SqlParameter("#old", model.Duplicate));
comm.Parameters.Add(new System.Data.SqlClient.SqlParameter("#new", model.Primary));
_dataAccessService.ExecuteSql(conn, comm);
Version 2:
comm.Parameters.AddWithValue("#old", model.Duplicate);
comm.Parameters.AddWithValue("#new", model.Primary);
Version 3:
comm.Parameters.Add("#old", System.Data.SqlDbType.Int);
comm.Parameters[0].Value = model.Duplicate;
comm.Parameters.Add("#new", System.Data.SqlDbType.Int);
comm.Parameters[1].Value = model.Primary;
Lastly, here's the code in the _dataAccessService.ExecuteSql(conn, comm) call:
public void ExecuteSql(SqlConnection connection, SqlCommand command, bool closeConnection = true)
{
if (connection == null)
throw new ArgumentNullException("connection");
if (command == null)
throw new ArgumentNullException("command");
try
{
if (connection.State != ConnectionState.Open)
connection.Open();
try
{
command.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
if (closeConnection)
command.Dispose();
}
}
catch (Exception ex)
{
throw new Exception("Sorry, an error occurred ExecuteSql: " + ex.Message, ex);
}
finally
{
if (closeConnection)
connection.Dispose();
}
}
Note: I have confirmed that the values for both '#old' and '#new' are set when it gets to the ExecuteNonQuery() line.
Edit: Here's the full code, as it exists:
// Here we need to execute the "FixDuplicate" stored procedure
var sql = "FixDuplicate";
var conn = _dataAccessService.GetConnection("");
var comm = _dataAccessService.GetCommand(conn, sql, System.Data.CommandType.StoredProcedure);
//comm.Parameters.AddWithValue("#old", model.DuplicateWrestler);
//comm.Parameters.AddWithValue("#new", model.PrimaryWrestler);
comm.Parameters.Add("#old", System.Data.SqlDbType.Int);
comm.Parameters[0].Value = model.DuplicateWrestler;
comm.Parameters.Add("#new", System.Data.SqlDbType.Int);
comm.Parameters[1].Value = model.PrimaryWrestler;
_dataAccessService.ExecuteSql(conn, comm);
Probably your model.Duplicate is null. In this case value of parameter will not be set.
If you need to pass null to SqlParameter.Value, use DBNull.Value.
See SqlParameter.Value for reference.
I believe you need to specify a command type:
command.CommandType = CommandType.StoredProcedure;
I suggest you to check with Profiler if old parameter is set or not.
And also try to run this procedure from SQL Server Management Studio to be sure it's working fine.
In our project's current state, we have at least one method used to call each stored procedure that we have created on the database server. Since these methods are pretty lengthy, involving creating each SqlParameter and then passing them to the database connection, I was considering creating a method that would generalize the process for our needs.
This is what I've come up with so far:
public static void UpdateTableTest(string procedureName, params object[] paramList)
{
if (sessionID == -1)
GetActiveSession();
SqlConnection scn = new SqlConnection(GetConnectionString());
try
{
scn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = scn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = procedureName;
SqlCommandBuilder.DeriveParameters(cmd);
for (int i = 0; i < paramList.Length; i++)
{
cmd.Parameters[i+1].Value = paramList[i];
}
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
scn.Close();
}
}
Aside from problems that I will run in to for different query types, and for query types that I will need to return some data from, is there anything inherently wrong with this method of executing stored procedures? Should I stick with an individual method for each stored procedure?
You can consider using Enterprise library or
SQLHelpers
available online.
example
DataSet dsUserInfo = new DataSet();
dsUserInfo = SqlHelper.ExecuteDataSet("Select * from UserInfo", CommandType.Text);
MyDataGridview.DataSource = dsUserInfo.Tables[0];
Or if you want to get rid of this even, you can go for ORM like EF suggested by John
I have a very simple Update statement that will update mail server settings and network credentials info... Query works fine when I run it in Access but C# keeps giving me the error stating that my SQL Syntax is wrong ... I have a dataaccess layer (dal class) and Update instance method pasted belows ... But the problem must be sth else cuz I have updated lots of stuff this way but this time it just won't do .. any clues will be greatly appreciated. Thx in advance.
Update instance method in DAL class .. (this is supposed to be a Data Access Layer :) I'm just a management graduate :P
public int UpdateRow(string Query, bool isSP, params OleDbParameter[] args)
{
int affectedRows = -1;
using (con = new OleDbConnection(connStr))
{
using (cmd = con.CreateCommand())
{
cmd.CommandText = Query;
if (isSP)
{
cmd.CommandType = CommandType.StoredProcedure;
}
if (args != null)
{
foreach (OleDbParameter prm in args)
{
cmd.Parameters.Add(prm);
}
}
try
{
con.Open();
affectedRows = cmd.ExecuteNonQuery();
}
catch(OleDbException ex)
{
throw ex;
}
catch (Exception ex)
{
throw ex;
}
}
}
return affectedRows;
}
And the ASP.NEt codebehind that will do the updating =
protected void Update_Click(object sender, EventArgs e) {
DAL dal = new DAL();
string upt = string.Format("UPDATE [MailConfig] SET Server='{0}', Username='{1}', Password='{2}', AddressFrom='{3}', DisplayName='{4}'",server.Text,username.Text,password.Text,replyto.Text,displayname.Text);
dal.UpdateRow(upt,false,null);
LoadData();
}
peace!
Trying wrapping your field names in [ ]. I have had problems in the past with certain field names such as a username and password and count, etc, being recognized as reserved words and screwing up the sql giving me an error.
First off - don't use string.Format here. Use parameters, and add parameters to the command. Right now, you are wide open to SQL injection attacks. Think "Bobby Tables".
Re "stating that my SQL Syntax is wrong" - can you please quote the exact error?
First of all, you have no where clause in your Update, so it will update all rows, and violate key constraints causing an error, if you have any.
Second, running that kind of code makes you very vunerable to SQL Injection, if someone enters a username that has a sql command embedded in it, you could lose all your data.
You should use parameterized queries. You specify your parameters in the sql command with #paramname instead of using {4}, and then with the command object do accessCommand.parameters.AddWithValue("#paramname", value)
You are using a CommandType of StoredProcedure, but your query is not a stored procedure name, its a sql query without a where clause.
UPDATE [MailConfig]
SET Server='{0}',
Username='{1}',
Password='{2}',
AddressFrom='{3}',
DisplayName='{4}'"
So you need to remove the command type line, or change it to a correct command type CommandType.Text, and add a Where clause specifying what rows are to be affected.
I don't think Access even has Stored Procedures, so there's no using to use that command type with it.
An example of a command that does use stored procedures would be something like:
string sqlCommString = "QCApp.dbo.ColumnSeek";
SqlCommand metaDataComm = new SqlCommand(sqlCommString, sqlConn);
metaDataComm.CommandType = CommandType.StoredProcedure;
The command string for that type is just the name of the stored proc.