Database access class using VB.NET
Now that's some coincidence! No later than this week I wrote an ADODB "wrapper" for some vb6 legacy code (here). This looks very much similar, only for ADO.NET.

I don't like the name. DB is not respecting the PascalCase naming convention for VB.NET classes (same in C#) - I realize it's a short handy name, but it looks like a variable's name. I'd rename the class to, say, AdoCommandBuilder; the name of the object should say what the object's role is. In this case, building an ADO.NET command.

I might be completely wrong here, but it seems to me that a thread entering BuildCommand from ExecuteReader would open up a connection, and then when the function returns, the connection would be disposed before the client code can start iterating the reader. Thus I wouldn't wrap an IDisposable in a Using block if I'm going to be returning it.

Anyway your command is being disposed twice. Once in BuildCommand:

        Using cmd As SqlCommand = con.CreateCommand()
            cmd.CommandType = CommandType.StoredProcedure
            cmd.CommandText = cmdTxt
            AddParameters(cmd, params)
            con.Open()
            Return cmd
        End Using '&lt;&lt;&lt;&lt;&lt;&lt; here


...and once more in the ExecuteXxxxx methods:

    Using cmd As SqlCommand = BuildCommand(cmdTxt, params)
        Return cmd.ExecuteReader()
    End Using ' &lt;&lt;&lt;&lt;&lt;&lt; here too!


I'd remove the Using cmd As SqlCommand from the CreateCommand method.

I agree with @Malachi, that BuildCommand shouldn't be opening the connection - its concern is building a command, so it should be taking a connection as a parameter; by doing that you enable extending your class with methods that take a connection, which enables running your commands in a transaction.

Hence, I think I would drop the parameterized constructor, add a Connect(connectionString As String) method instead, encapsulate the connection (, implement IDisposable) and give each ExecuteXxxxxx method an overload that takes an IDbConnection parameter; if you're not going to be taking in a connection, then you should own the whole process and return the data, not the reader itself - the idea is that you generally want the object that creates an IDisposable to be the one calling Dispose on it, so I'd only return a SqlDataReader when the client code owns the connection.