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.
Related
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.
I am trying to execute a stored procedure with parameters, and get the results into a DataTable; but after execution, I get this:
this is the screen
I can get IDataRecord but I can't IDataReader - why? What do I miss? Thanks
public DataTable ExecuteProcedureTest(string storedProcedure, Dictionary<Filter, object> filterValue)
{
var parameters = GetParams(filterValue);
var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["testconn"].ConnectionString);
var cmd = sqlConnection.CreateCommand();
SqlDataReader reader;
IDataReader dataReader;
IDataRecord[] dataRecords;
var table = new DataTable();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcedure;
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
try
{
sqlConnection.Open();
reader = cmd.ExecuteReader();
dataRecords = reader.OfType<IDataRecord>().ToArray();
table.Load(reader);
}
catch (Exception ex)
{
throw ex;
}
finally
{
sqlConnection.Dispose();
}
//var count = dataRecords.Count();
return table;
}
If your goal is to fill a DataTable from a SqlCommand, use a SqlDataAdapter instead of a SqlDataReader. Here is a handy extension method:
public static class SqlExtensions
{
public static DataTable ExecuteDataTable(this SqlCommand command)
{
DataTable table = new DataTable();
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
{
dataAdapter.Fill(table);
}
return table;
}
}
Then from your code you can use it like this:
try
{
sqlConnection.Open();
table = cmd.ExecuteDataTable();
}
finally
{
sqlConnection.Dispose();
}
I am running an sql database for movies and I am working on this function so that whenever a user checks out a movie, the movie would be updated saying it has been checked out, then the checked out movie would be added to a table for checked out movies. I have a code that runs without any errors but my checked out movie does not get added to my checked out table. Code for the gridview that displays the selected movie below:
<asp:ListBox ID="CheckOutList" runat="server" OnSelectedIndexChanged="Get_data" AutoPostBack="true">
</asp:ListBox>
<asp:Panel ID="panel5" runat="server" Visible="false">
<asp:GridView id="one_data" AutoGenerateColumns="false" runat="server" DataKeyNames="MovieID">
<Columns>
<asp:BoundField DataField="MovieID"
HeaderText="Movie ID"/>
<asp:BoundField DataField="MovieTitle"
HeaderText="Movie"/>
<asp:BoundField DataField="DateChecked"
HeaderText="Date Checked"/>
<asp:BoundField DataField="CheckedOut"
HeaderText="Checked Out"/>
</Columns>
</asp:GridView>
<asp:Button runat="server" Text="Choose another Movie" OnClick="GoBack" />
<asp:Button runat="server" Text="Check Out" OnClick="CheckOut" />
</asp:Panel>
CS code for checking out the movie:
public void CheckOut(object sender, EventArgs e)
{
get_connection();
try
{
connection.Open();
command = new SqlCommand("UPDATE Content SET DateChecked=#DateChecked, CheckedOut=#CheckedOut WHERE MovieID=#MovieID", connection);
command.Parameters.AddWithValue("#DateChecked", DateTime.Now);
command.Parameters.AddWithValue("#CheckedOut", 'Y');
//command.Parameters.AddWithValue("#MovieID",);
command.Parameters.AddWithValue("#MovieID", CheckOutList.SelectedValue);
reader = command.ExecuteReader();
one_data.DataSource = reader;
one_data.DataBind();
reader.Close();
command = new SqlCommand("INSERT INTO checkout (MovieID, SubscriberID) VALUES #MovieID, #SubscriberID", connection);
command.Parameters.AddWithValue("#MovieID", CheckOutList.SelectedValue);
command.Parameters.AddWithValue("#SubscriberID", loginName.Text);
command.ExecuteNonQuery();
}
catch (Exception err)
{
// Handle an error by displaying the information.
lblInfo.Text = "Error reading the database. ";
lblInfo.Text += err.Message;
}
finally
{
connection.Close();
lblInfo.Text = "Movie Checked Out";
}
}
The UPDATE SQL statement does work saying the movie has been taken but the movie does not get added to the checked out table.
I see some missing concept.
why update use command.ExecuteReader(); while insert use command.ExecuteNonQuery(); .
I think you should use
ExecuteNonQuery
INSERT INTO checkout (MovieID, SubscriberID) VALUES #MovieID, #SubscriberID .
This sql syntax need bracket for values :
INSERT INTO checkout (MovieID, SubscriberID) VALUES (#MovieID, #SubscriberID)
I hope this solve yours.
I think you better execute coding in the transaction block. also you can update as following examlpe with ";"
connection.ConnectionString = connectionString;
command.CommandText = #"
UPDATE MultiStatementTest SET somevalue = somevalue + 1;
UPDATE MultiStatementTest SET" + (generateError ? "WONTWORK" : "") +
" somevalue = somevalue + 2;";
command.CommandType = System.Data.CommandType.Text;
command.Connection = connection;
Can I execute multiple SQL statements?
Of course you can! You can execute it in a single or multiple SqlCommand. :)
The UPDATE SQL statement does work saying the movie has been taken but
the movie does not get added to the checked out table
Are you using a local database? If yes, check out Data not saving permanently to SQL table.
Anyway, I would like to my code for data access which could help you in your development.
Disclaimer: I know that using SqlCommand as parameter is better but I got lazy so here's the string version.
public interface IDAL
{
void BeginTransaction();
void EndTransaction();
void SaveChanges();
DataTable RetrieveData(string query, [CallerMemberName] string callerMemberName = "");
string RetrieveString(string query, [CallerMemberName] string callerMemberName = "");
bool ExecuteNonQuery(string query, [CallerMemberName] string callerMemberName = "");
bool ExecuteNonQuery(string query, object[] parameters, [CallerMemberName] string callerMemberName = "");
}
public class MSSQLDAL : IDAL, IDisposable
{
private bool disposed = false;
private string _connectionString { get; set; }
private SqlTransaction _transaction { get; set; }
private SqlConnection _connection { get; set; }
private IsolationLevel _isolationLevel { get; set; }
private bool _isCommitted { get; set; }
public string ConnectionString
{
get { return _connectionString; }
}
public MSSQLDAL(string connectionString)
{
this.connectionString = _connectionString;
this._connection = new SqlConnection();
this._connection.ConnectionString = this._connectionString;
this._isolationLevel = IsolationLevel.ReadCommitted;
this._isCommitted = false;
}
public void BeginTransaction()
{
this.Open();
}
public void EndTransaction()
{
this.Close();
}
public void SaveChanges()
{
if(_transaction != null)
{
_transaction.Commit();
this._isCommitted = true;
}
this.EndTransaction();
}
public DataTable RetrieveData(string query, [CallerMemberName] string callerMemberName = "")
{
DataTable dataTable = new DataTable();
try
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = _connection;
command.Transaction = _transaction;
command.CommandText = query;
command.CommandType = CommandType.Text;
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
{
dataAdapter.Fill(dataTable);
}
}
//this.AuditSQL(query, string.Empty);
}
catch (Exception ex)
{
this.AuditSQL(query, ex.Message, callerMemberName);
}
return dataTable;
}
public string RetrieveString(string query, [CallerMemberName] string callerMemberName = "")
{
string text = string.Empty;
try
{
using (SqlCommand oracleCommand = new SqlCommand())
{
oracleCommand.Connection = _connection;
oracleCommand.Transaction = _transaction;
oracleCommand.CommandText = query;
oracleCommand.CommandType = CommandType.Text;
using (SqlDataReader dataReader = oracleCommand.ExecuteReader())
{
dataReader.Read();
text = dataReader.GetValue(0).ToString();
}
}
//this.AuditSQL(query, string.Empty);
}
catch (Exception ex)
{
this.AuditSQL(query, ex.Message, callerMemberName);
}
return text;
}
public bool ExecuteNonQuery(string query, [CallerMemberName] string callerMemberName = "")
{
bool success = false;
try
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = _connection;
command.Transaction = _transaction;
command.CommandText = query;
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();
}
//this.AuditSQL(query, string.Empty);
success = true;
}
catch (Exception ex)
{
this.AuditSQL(query, ex.Message, callerMemberName);
success = false;
}
return success;
}
public bool ExecuteNonQuery(string query, object[] parameters, [CallerMemberName] string callerMemberName = "")
{
bool success = false;
try
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = _connection;
command.Transaction = _transaction;
command.CommandText = query;
command.CommandType = CommandType.Text;
command.Parameters.AddRange(parameters);
command.ExecuteNonQuery();
}
//this.AuditSQL(query, string.Empty);
success = true;
}
catch (Exception ex)
{
this.AuditSQL(query, ex.Message, callerMemberName);
success = false;
}
return success;
}
private void Open()
{
if(_connection.State == ConnectionState.Closed)
{
_connection.Open();
_transaction = _connection.BeginTransaction(_isolationLevel);
}
}
private void Close()
{
if (!this._isCommitted)
{
if (this._transaction != null)
{
this._transaction.Rollback();
}
}
if(this._connection.State == ConnectionState.Open)
{
this._connection.Close();
}
}
private void AuditSQL(string query, string message, string callerMemberName = "")
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("**************************************************************************************************");
stringBuilder.AppendLine(string.Format("DATETIME: {0}", DateTime.Now.ToString("MM/dd/yyyy HHmmss")));
stringBuilder.AppendLine(string.Format("SQL: {0}", query));
stringBuilder.AppendLine(string.Format("MESSAGE: {0}", message));
if (!string.IsNullOrWhiteSpace(callerMemberName))
{
stringBuilder.AppendLine(string.Format("METHOD: {0}", callerMemberName));
}
stringBuilder.AppendLine("**************************************************************************************************");
Logger.WriteLineSQL(stringBuilder.ToString()); // Log the query result. Add an #if DEBUG so that live version will no longer log.
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if (!this._isCommitted)
{
if (this._transaction != null)
{
this._transaction.Rollback();
}
}
this._transaction.Dispose();
this._connection.Dispose();
}
// Free your own state (unmanaged objects).
// Set large fields to null.
// Free other state (managed objects).
this._transaction = null;
this._connection = null;
disposed = true;
}
}
}
Sample usage:
public void CheckOut(object sender, EventArgs e)
{
string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; // Assuming it is in your web.config
try
{
using(MSSQLDAL dal = new MSSQLDAL(connectionString))
{
dal.BeginTransaction();
string updateQuery = "UPDATE Content SET DateChecked=#DateChecked, CheckedOut=#CheckedOut WHERE MovieID=#MovieID";
SqlParameter uDateChecked = new SqlParameter("DateChecked", SqlDbType.DateTime);
uDateChecked = DateTime.Now;
SqlParameter uCheckedOut = new SqlParameter("CheckedOut", SqlDbType.VarChar);
uCheckedOut = 'Y';
SqlParameter uMovieID = new SqlParameter("MovieID", SqlDbType.Int);
uMovieID = CheckOutList.SelectedValue;
ICollection<SqlParameter> updateParameters = new List<SqlParameter>();
updateParameters.Add(uDateChecked);
updateParameters.Add(uCheckedOut);
updateParameters.Add(uMovieID);
bool updateSuccessful = dal.ExecuteNonQuery(updateQuery, updateParameters.ToArray());
string insertQuery = "INSERT INTO checkout (MovieID, SubscriberID) VALUES (#MovieID, #SubscriberID)";
SqlParameter iSubscriberID = new SqlParameter("SubscriberID", SqlDbType.VarChar);
iSubscriberID = loginName.Text;
SqlParameter iMovieID = new SqlParameter("MovieID", SqlDbType.Int);
iMovieID = CheckOutList.SelectedValue;
ICollection<SqlParameter> insertParameters = new List<SqlParameter>();
insertParameters.Add(iSubscriberID);
insertParameters.Add(iMovieID);
bool insertSuccessful = dal.ExecuteNonQuery(insertQuery, insertParameters.ToArray());
if(updateSuccessful && insertSuccessful)
{
dal.SaveChanges();
lblInfo.Text = "Movie Checked Out";
}
else
{
lblInfo.Text = "Something is wrong with your query!";
}
}
}
catch(Exception ex)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("Error reading the database.");
sb.AppendLine(ex.Message);
if(ex.InnerException != null)
sb.AppendLine(ex.InnerException.Message);
lblInfo.Text = sb.ToString();
}
}
How can I execute multiple SQL statements in a single command?
You simply need to encapsulate your queries with a BEGIN and END;.
Ex:
BEGIN
SELECT 'A';
SELECT * FROM TableA;
END;
Take note that you need to have ; after your statements. I'd use a StringBuilder to write my long queries if I were you. Also, sending multiple queries as one is only useful if you are not reading any data.
What's the IDAL interface for?
In some of my projects I had to work with different databases. Using the same interface, I am able to create a DAL class for Oracle, MSSql and MySql with very minimal code change. It is also the OOP way. :)
Please change the code like this and try.change the reader.close() after executenonquery().
try
{
connection.Open();
command = new SqlCommand("UPDATE Content SET DateChecked=#DateChecked, CheckedOut=#CheckedOut WHERE MovieID=#MovieID", connection);
command.Parameters.AddWithValue("#DateChecked", DateTime.Now);
command.Parameters.AddWithValue("#CheckedOut", 'Y');
//command.Parameters.AddWithValue("#MovieID",);
command.Parameters.AddWithValue("#MovieID", CheckOutList.SelectedValue);
reader = command.ExecuteReader();
one_data.DataSource = reader;
one_data.DataBind();
command = new SqlCommand("INSERT INTO checkout (MovieID, SubscriberID) VALUES #MovieID, #SubscriberID", connection);
command.Parameters.AddWithValue("#MovieID", CheckOutList.SelectedValue);
command.Parameters.AddWithValue("#SubscriberID", loginName.Text);
command.ExecuteNonQuery();
reader.Close();
}
I finally found an answer after reading all the posts and found that this actually got my INSERT to work
try
{
connection.Open();
command = new SqlCommand("UPDATE Content SET DateChecked=#DateChecked, CheckedOut=#CheckedOut WHERE MovieID=#MovieID", connection);
command.Parameters.AddWithValue("#DateChecked", DateTime.Now);
command.Parameters.AddWithValue("#CheckedOut", 'Y');
//command.Parameters.AddWithValue("#MovieID",);
command.Parameters.AddWithValue("#MovieID", CheckOutList.SelectedValue);
//reader = command.ExecuteReader();
command.ExecuteNonQuery();
one_data.DataSource = reader;
one_data.DataBind();
connection.Close();
connection.Open();
command = new SqlCommand("INSERT INTO checkout (MovieID, SubscriberID) VALUES (#MovieID, #SubscriberID)", connection);
command.Parameters.AddWithValue("#MovieID", CheckOutList.SelectedValue);
command.Parameters.AddWithValue("#SubscriberID", loginName.Text);
command.ExecuteNonQuery();
//reader.Close();
}
I am using a SqlHelper class which has common methods for CRUD operations.
public static void Fill(DataSet dataSet, String procedureName)
{
SqlConnection oConnection = new SqlConnection(DBInterface.ConnectionString);
SqlCommand oCommand = new SqlCommand(procedureName, oConnection);
oCommand.CommandType = CommandType.StoredProcedure;
SqlDataAdapter oAdapter = new SqlDataAdapter();
oAdapter.SelectCommand = oCommand;
oConnection.Open();
using (SqlTransaction oTransaction = oConnection.BeginTransaction())
{
try
{
oAdapter.SelectCommand.Transaction = oTransaction;
oAdapter.Fill(dataSet);
oTransaction.Commit();
}
catch
{
oTransaction.Rollback();
throw;
}
finally
{
if (oConnection.State == ConnectionState.Open)
oConnection.Close();
oConnection.Dispose();
oAdapter.Dispose();
}
}
}
Now in my code, I am calling this method as,
private void BindCustomers()
{
DataSet dsCust = new DataSet();
SqlHelper.Fill(dsCust, "getCustomers");
--then I bind this dataset to datagridview
}
This all works fine. Now I want to update the data in the database. But I am confused how do I call DataAdatpaer.Update(dataset) here to update the changes made in datagridview into database. Is this possible here? Or I need to do it conventionally to find the updated row and call the ExecuteNonQuery function in the SqlHelper? Is there anything which can be done to use dataadapter.update(ds)
Thanks
You don't need to hide data adapter, or if for any reason you did so, you need to expose a method in your class to push updates to server.
Example
Public class SqlHelper
{
string commandText;
string connectionString;
public SqlHelper(string command, string connection)
{
commandText = command;
connectionString = connection;
}
public DataTable Select()
{
var table = new DataTable();
using (var adapter = new SqlDataAdapter(this.commandText, this.connectionString))
adapter.Fill(table)
return table;
}
public void Update(DataTable table)
{
using (var adapter = new SqlDataAdapter(this.commandText, this.connectionString))
{
var builder = new SqlCommandBuilder(adapter);
adapter.Update(table);
}
}
}
By calling this method in your code you can perform all crud operation select, update, delete and insert. you just need to pass connection string, procedure name and parameters list. Using this method you will retrieve data in the DataTable.if anyone want Dataset(Multiple Result) then just need to replace DataSet on the place of DataTable
SqlConnection conn = new SqlConnection("Your ConnectionString");
public DataTable ExecuteDataTable(string ProcedureName, SqlParameter[] _Param)
{
try
{
DataTable dataTable = new DataTable();
SqlCommand cmd = new SqlCommand(ProcedureName, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
if (_Param is not null)
{
for (int i = 0; i < _Param.Length; i++)
{
if (_Param[i].ParameterName is not null)
{
if (_Param[i].Value is not null)
{
cmd.Parameters.AddWithValue(_Param[i].ParameterName, _Param[i].Value);
}
else
{
cmd.Parameters.AddWithValue(_Param[i].ParameterName, DBNull.Value);
}
}
}
}
conn.Open();
SqlDataAdapter DA = new SqlDataAdapter(cmd);
DA.Fill(dataTable);
conn.Close();
return dataTable;
}
catch (Exception ex)
{
conn.Close();
throw;
}
}
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;
}
}