2

I am starting to encapsulate my queries in a single parameterized query class

Now can you please evaluate my classes for performance security and every other aspect possible ?

Do you have any suggestions ?

Here my select class

public static DataSet cmd_SelectQuery(string srCommandText, List<string> lstParameterNames, List<string> lstParameters)
{
    DataSet dsCmdPara = new DataSet();
    try
    {
        using (SqlConnection connection = new SqlConnection(DbConnection.srConnectionString))
        {
            using (SqlCommand cmd = new SqlCommand(srCommandText, connection))
            {
                cmd.CommandType = CommandType.Text;
                for (int i = 0; i < lstParameterNames.Count; i++)
                {
                    cmd.Parameters.AddWithValue(lstParameterNames[i], lstParameters[i]);
                }
                connection.Open();
                using (SqlDataAdapter sqlDa = new SqlDataAdapter(cmd))
                {
                    sqlDa.Fill(dsCmdPara);
                    return dsCmdPara;
                }
            }
        }
    }
    catch (Exception E)
    {
        csPublicFunctions.insertIntoTblSqlErrors(srCommandText + " " + E.Message.ToString());
    }
    return dsCmdPara;
}

And here my update,delete class

public static void cmd_UpdateDeleteQuery(string srCommandText, List<string> lstParameterNames, List<string> lstParameters)
{
    try
    {
        using (SqlConnection connection = new SqlConnection(DbConnection.srConnectionString))
        {
            using (SqlCommand cmd = new SqlCommand(srCommandText, connection))
            {
                cmd.CommandType = CommandType.Text;
                for (int i = 0; i < lstParameterNames.Count; i++)
                {
                    cmd.Parameters.AddWithValue(lstParameterNames[i], lstParameters[i]);
                }
                connection.Open();
                cmd.ExecuteNonQuery();
            }
        }
    }
    catch (Exception E)
    {
        csPublicFunctions.insertIntoTblSqlErrors(srCommandText + " " + E.Message.ToString());
    }
}

Thanks a lot for answers

6
  • What if one of your parameters is not a string? (for example select * from table where ID = @tableID and ID is a numeric field) Commented Dec 24, 2012 at 21:04
  • How you can pass parameters rather than string type? Commented Dec 24, 2012 at 21:05
  • Well obviously i can not pass :D You can post your suggestion class as answer Commented Dec 24, 2012 at 21:05
  • Make your paramter IList<object> lstParameters or simply IList lstParameters. IList allows you to pass lists as well as arrays and object allows you to pass the parameters in the correct type. Commented Dec 24, 2012 at 21:08
  • @Steve that does not causes any problem as long as the parameter i gave class is integer. Commented Dec 24, 2012 at 21:08

3 Answers 3

2

Two quick suggestions since I'm writing this on a phone.

  1. Take in objects, not string
  2. Taking in params object[] as the parameter list might make your methods a little more natural to use.
Sign up to request clarification or add additional context in comments.

2 Comments

thanks but what do you mean by "params object[] as the parameter list might make your methods a little more natural to use." do you mean each object should be a list of objects ?
Params lets you do something like this: Query("select * from order where id = {0} and status = {1}", id, 5); Notice I didn't have to new up a list to put the params inside.
1

The code is valid and correct as it stands. You asked for feedback, so I have the following points.

(1) In the code where you are building up the parameters, it's a good idea to specify the data type.

for (int i = 0; i < lstParameterNames.Count; i++)
{
    var parameter = cmd.Parameters.AddWithValue(lstParameterNames[i], lstParameters[i]);
    parameter.SqlDbType = SqlDbType.NVarChar; // or whatever type you need
}

(2) You don't need to explicitly open/close the connection, as the Fill method does that for you.

connection.Open();
using (SqlDataAdapter sqlDa = new SqlDataAdapter(cmd))
{
    sqlDa.Fill(dsCmdPara);
    connection.Close();
    return dsCmdPara;
}

(3) If you are only going to have one table, use a DataTable instead of a DataSet. It will be faster and less complex.

(4) This is more of a style point, but I find it is very helpful to explicitly close your connections. If there is an exception in the closing, having the line number (via the pdb) is very helpful. Also, it helps make sure you don't leak connections if you forget a using.


Edit

I want to clarify point 4. Assume that the when a connection in closed, the cleanup caused an exception. If you don't explicitly close the connection, the exception would be raised in the Dispose method, which might be doing a bunch of other work. This makes it harder to see what I did to cause the problem.

Take this simple example. There is an underlying resource that needs to be cleaned up (the entire reason for Dispose), and it throws an exception.

public class Resource: IDisposable
{
    public void Close()
    {
        CleanupMemory();
    }

    private void CleanupMemory()
    {
        throw new Exception();
    }

    public void Dispose()
    {
        CleanupMemory();
    }
}

The (cleaned up) stack trace for the two different approaches are:

using (var r = new Resource())
{
    r.Close();
}

   at ConsoleApplication1.Resource.CleanupMemory() in Program.cs:line 31
   at ConsoleApplication1.Resource.Close() in Program.cs:line 26
   at ConsoleApplication1.Program.Main(String[] args) Program.cs:line 16

versus

using (var r = new Resource())
{

}


   at ConsoleApplication1.Resource.CleanupMemory() in Program.cs:line 35
   at ConsoleApplication1.Resource.Dispose() in Program.cs:line 40
   at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 18

In the first example, I know that my calling Close caused the exception, I have a place to start debugging. If I only know that the exception was thrown, I need to completely rely on the information in the exception. I have no other context. And most exception messages are not especially clear. :)

Both are totally correct, just different.

Erick

4 Comments

thanks a lot for suggestions. as for stands assume that an error happened inside using. wouldn't it close connection ? Also it seems like my system is wasted a lot with datasets since i built it that way ^^ even though almost 99% time i select only 1 table
It's not so much that the connection won't be closed, but that any exception would be raised from inside the code generated by the using block. When this happens, you don't have access to your local variables, making debugging more difficult.
what do you mean by "It's not so much that the connection won't be closed"
If there are using blocks for every disposable object, then the resources will be cleaned up. This includes closing the connection.
-1
public DataTable Get_DTable(String Query, Dictionary<String, String> Parameters)
    {
        try
        {
            using (con = new SqlConnection(cls_Connection.URL()))
            {
                if (con.State == 0)
                    con.Open();
                using (cmd = new SqlCommand(Query, con))
                {
                    foreach (KeyValuePair<string, string> item in Parameters)
                    {
                        cmd.Parameters.AddWithValue(item.Key, item.Value);
                    }

                    using (da = new SqlDataAdapter(cmd))
                    {
                        using (dt = new DataTable())
                        {
                            da.Fill(dt);
                            if (dt.Rows.Count > 0)
                            {
                                return dt;
                            }
                        }
                    }
                }
            }
        }
        catch (Exception exp)
        {
            MessageBox.Show(exp.Message,
                            "Information",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information);
        }
        return null;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.