Search code examples
c#sql-serversqlcommandsqldataadapterexecutereader

Would executing the SqlCommand be completely moot/redundant, and slow things down?


Thanks to some tips and reminders here, I changed my code from this kludgy mess:

try
{
    DataSet dsUsage = new DataSet();

    SqlConnection conn = new SqlConnection("SERVER=PROSQL05;DATABASE=platypusdata;UID=duckbill;PWD=poisonToe42;Connection Timeout=0");

    SqlDataAdapter da = new SqlDataAdapter();

    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = String.Format("Exec sp_ViewProductUsage_MappingRS '{0}', '{1}', '{2}'", mammal, dateBegin, dateEnd);
    da.SelectCommand = cmd;

    conn.Open();
    da.Fill(dsUsage);
    conn.Close();

    DataTable dtUsage = dsUsage.Tables[0];

    if (dtUsage.Rows.Count > 0)
    {
        foreach (DataRow productUsageByMonthDataRow in dtUsage.Rows)
        {
            . . .

...to this:

try
{
    SqlDataAdapter da = new SqlDataAdapter();
    DataSet dsUsage = new DataSet();

    using (SqlConnection conn = new SqlConnection(UsageRptConstsAndUtils.PlatypusConnStr))
    {
        using (SqlCommand cmd = new SqlCommand("sp_ViewProductUsage_MappingRS", conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add("@Unit", SqlDbType.VarChar).Value = _unit;
            cmd.Parameters.Add("@BegDate", SqlDbType.DateTime).Value = dtBegin;
            cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = dtEnd;

            da.SelectCommand = cmd;

            conn.Open();
            //cmd.ExecuteReader(); <- Is this even necessary?
            da.Fill(dsUsage);
        }
    }

    DataTable dtUsage = dsUsage.Tables[0];

    if (dtUsage.Rows.Count > 0)
    {
        // Populate the cells
        foreach (DataRow productUsageByMonthDataRow in dtUsage.Rows)
        {
            . . .

Note that I have SqlCommand's ExecuteReader commented out in the new code because it seems unnecessary due to the SqlDataAdapter being provided the SqlCommand. It works fine. So: am I correct in assuming I can remove cmd.ExecuteReader() altogether? Is there any benefit in retaining it, or would that be totally redundant and create "busy work" for the process?

UPDATE

So, to pass an array of SqlParameter (to the ExecuteDataSet method in MethodMan's answer), I take it that I would first have to do something like:

SqlParameter sqlp = new SqlParameter();
sqlp.ParameterName = "Unit";
sqlp.Value = _unit;
cmd.Parameters.Add(sqlp);

...etc. (and then add them to an array - or, possibly better a generic list of SqlParameter).

UPDATE 2

I just ran into this for the first time: if you use MethodMan's example (which I do) and you use a parameterless query, you need to bypass the parameter-adding loop like so:

if (null != parameters)
{
    foreach (var item in parameters)
    {
        cmd.Parameters.Add(item);
    }
}

Solution

  • I would personally create a SqlDBHelper class and pass call the stored procedure using a method such as this

    public static class SqlDBHelper
    {
        public static DataSet ExecuteDataSet(string sql, CommandType cmdType, params SqlParameter[] parameters)
        {
            using (DataSet ds = new DataSet())
            using (SqlConnection connStr = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString))
            using (SqlCommand cmd = new SqlCommand(sql, connStr))
            {
                cmd.CommandType = cmdType;
                foreach (var item in parameters)
                {
                    cmd.Parameters.Add(item);
                }
    
                try
                {
                    cmd.Connection.Open();
                    new SqlDataAdapter(cmd).Fill(ds);
                }
                catch (SqlException ex)
                {
                    //log to a file or write to Console for example
                    Console.WriteLine(ex.Message);
                }
                return ds;
            }
        }
    }
    

    If you want to return a DataTable then change the return type in the Method signature and call the following in the return statement below

    public static DataTable ExecuteDataSet(string sql, CommandType cmdType, params SqlParameter[] parameters)
    
    return ds.Tables[0];
    

    Here is an example on how you would call the method

    someDataTable = SqlDBHelper.ExecuteDataSet("sp_ViewProductUsage_MappingRS", CommandType.StoredProcedure,
                new SqlParameter() { ParameterName = "@Unit", SqlDbType = SqlDbType.VarChar, Value = _unit },
                new SqlParameter() { ParameterName = "@BegDate", SqlDbType = SqlDbType.DateTime, Value = dtBegin },
                new SqlParameter() { ParameterName = "@EndDate", SqlDbType = SqlDbType.DateTime, Value = dtEnd }
                );