5
\$\begingroup\$

I am upgrading an old massive website that is a Classic ASP \ ASP.NET hybrid. I still have a long way to MVC.

Right now I want to convert all code that uses ODBC to the mysql connector specific code.

I've made these 2 functions:

1:

DataTable GetData(string query, List<MySqlParameter> sqlParams, string sComment="")
{
    DataTable dt_tmp = new DataTable();

    if (sqlParams==null)
        sqlParams = new List<MySqlParameter>();

    Trace.Write(sComment, GenerateSQLString(query, sqlParams));
    using(MySqlDataReader myReader = MySqlHelper.ExecuteReader(sCon, query, sqlParams.ToArray()))
    {
        dt_tmp.Load(myReader, LoadOption.OverwriteChanges);
    }
    return dt_tmp;
}

2:

DataTable ReadData(string query, List<MySqlParameter> sqlParams, string sComment="")
{
    DataTable dt_tmp = new DataTable();

    if (sqlParams==null)
        sqlParams = new List<MySqlParameter>();

    Trace.Write(sComment, GenerateSQLString(query, sqlParams));

    using(MySqlConnection myConnection = new MySqlConnection(sCon))
    {
        using(MySqlCommand myCommand = myConnection.CreateCommand())
        {
            myCommand.CommandText = query;
            myCommand.Parameters.AddRange(sqlParams.ToArray());
            using (MySqlDataAdapter myAdapter = new MySqlDataAdapter(myCommand))
            {
                myAdapter.Fill(dt_tmp);
            }
        }
    }

    return dt_tmp;
}

Function #1: gets a ConstraintException (MaxLength) on a specific call... but otherwise performs very well.

Which one will perform better? (Ignoring the fact one throws an exception, which I can handle)

My goal is to have the connection open for the minimum amount of time possible so it won't use all connections from the pool.

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Hide and seek

The first method is shorter but is that a good thing? Compared to the second one it hides a few thing internally which can be either good or bad and i would say bad. To me this method looks like a core application logic which has to be crystal clear so i think you shold not prefer the shorter version.

But wait

The second one still has some coding issues but nothing catastrophe. I have changed it in some parts, lets see:

    private DataTable ReadData(string query, string sComment = "")
    {
        return ReadData(query, EmptyMySqlParameters, sComment);
    }

    DataTable ReadData(string query, ICollection<MySqlParameter> sqlParams, string sComment = "")
    {
        var dt = new DataTable();

        Trace.Write(sComment, GenerateSQLString(query, sqlParams));

        using (var myConnection = new MySqlConnection(sCon))
        {
            myConnection.Open();

            using (var myCommand = myConnection.CreateCommand())
            {
                myCommand.CommandText = query;

                foreach (var mySqlParameter in sqlParams)
                {
                    myCommand.Parameters.Add(mySqlParameter);
                }

                using (var myReader = myCommand.ExecuteReader())
                {
                   dt.Load(myReader, LoadOption.OverwriteChanges);
                }
            }
        }

        return dt;
    }

First i have introduced an overloaded method to remove the null check against the List (null object pattern for collections are the empty versions of them). Changed the type to ICollection which is more flexible and intruduced a new static member which get involved in the process where no parameter is passed (can be static for reading it is thread safe).

I also removed the AddRange call becouse internally it is interating through the parameters with a foreach loop but only works with Array type parameter so after introducing our foreach loop calling Add manually we have removed an extra ToArray() call which would involve an unnecessary memory copy in the background.

Also changed the fill of the DataTable to a more used way and the MySqlHelper.ExecuteReader() does the same thing too.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks a lot for taking the time to write that detailed answer. The reason why I am using that short method (#1) is because of this: dev.mysql.com/doc/connector-net/en/… . More precisely, this: "One approach that simplifies things is to avoid manually creating a MySqlConnection object. Instead use the overloaded methods that take a connection string as an argument. Using this approach, Connector/Net will automatically create, open, close and destroy connections, using the connection pooling system for best performance." \$\endgroup\$
    – Cornwell
    Commented Oct 30, 2014 at 11:45
  • \$\begingroup\$ With the using blocks you achieve the same thing. \$\endgroup\$
    – Peter Kiss
    Commented Oct 30, 2014 at 11:49
  • \$\begingroup\$ Humm... I still need to open the connection though. When running that function I get: "System.InvalidOperationException: Connection must be valid and open." in this line: "using (var myReader = myCommand.ExecuteReader())". Will it close it automatically after the using block? \$\endgroup\$
    – Cornwell
    Commented Oct 30, 2014 at 12:01
  • \$\begingroup\$ Added the Open call to my answer. Yes it will close the conntection but you can also specify a CommandBehavior in the ExecuteReader call (myCommand.ExecuteReader(CommandBehavior.CloseConnection)). \$\endgroup\$
    – Peter Kiss
    Commented Oct 30, 2014 at 12:05

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.