can someone tell me how to use a SQL Connection in C# correct?
Right now I am doing it like that:
//some Code here
using (var sqlConnection = DatabaseUtil.DatabaseUtil.CreateSqlConnection(connectionString))
{
var cmd = new SqlCommand();
DatabaseUtil.DatabaseUtil.InitializeSqlCommand(ref cmd, query, sqlConnection);
sqlConnection.Open();
using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
reader.Read();
if (reader.HasRows)
{
//some code here
}
reader.Close();
reader.Dispose();
}
sqlConnection.Close();
}
DatabaseUtil
is written in VB.NET . Here the Function CreateSqlConnection
:
Public Function CreateSqlConnection(connectionString As String) As SqlConnection
Dim result As SqlConnection
result = New SqlConnection(connectionString)
Return result
End Function
And here you can see the function InitializeSqlCommand
:
Public Sub InitializeSqlCommand(ByRef cmd As SqlCommand, query As String, sqlConnection As SqlConnection)
cmd.CommandText = query
cmd.CommandType = CommandType.Text
cmd.Connection = sqlConnection
End Sub
Am I doing it right ? Or do you have some suggestion for improvement for me?
I will be appreciative for every tip.
Ali
I doubt if you want DatabaseUtil
here; explicit creation with new
will do:
// If you don't want to hardcode connection's type - SqlConnection -
// (possible purpose of DatabaseUtil class) use dependency injection
using (var sqlConnection = new SqlConnection(connectionString)) {
sqlConnection.Open();
// sqlConnection.CreateCommand() - we can avoid dependency
// and don't hardcode SqlCommand as "new SqlCommand"
//DONE: wrap IDisposable into using, do not close it explicitly
using (var cmd = sqlConnection.CreateCommand()) {
cmd.CommandText = query;
//TODO: you may want to provide Parameters here
//DONE: wrap IDisposable into using, do not close it explicitly
using (var reader = cmd.ExecuteReader()) {
// reader.Read() returns true if record is read
// (i.e. we have at least one record)
if (reader.Read()) {
// We have at least one row
// some code here
}
}
}
}
In case you want to read several records not just a fact that query returns at least one record, turn if (reader.Read())
into while
:
...
//DONE: wrap IDisposable into using, do not close it explicitly
using (var reader = cmd.ExecuteReader()) {
// reader.Read() returns true if record is read
while (reader.Read()) {
// record has been read
// some code here
}
}
...
I need to start off by saying nothing in the original post is wrong , per se, and you could continue to use that code just fine.
But... we can still do better.
There is no need for the SqlCommand
argument to InitializeSqlCommand()
to pass by ref. IMO this is a mistake in the VB code. ByVal
is good enough here, and ByRef
exposes your command object to things you might not want.
In the CreateSqlConnection()
function, I tend to assume if you're creating a connection, you're going to want to open it soon, too. Plus, we can shorten the method some.
I also tend to either put my connection strings directly into my equivalent DatabaseUtil modules, or build the Module so it can load the string from a config file. I don't want to need to pass that data into the CreateSqlConnection()
method every time. Put these two paragraphs together like this:
Private ReadOnly Property ConnectionString As String
Get
Return "connection string here"
End Get
End Property
Public Function CreateSqlConnection() As SqlConnection
Dim result As New SqlConnection(ConnectionString)
result.Open()
Return result
End Function
It's a small thing, but SqlCommand
also implements IDisposble
, so ideally it will also be in a using
block. Really, there's nothing in the existing InitializeSqlCommand()
method you can't accomplish directly with the SqlCommand
constructor, as CommandType.Text
is already the default. Go ahead and import the DatabaseUtil
namespace, and you can put these two paragraphs together like this:
using (var sqlConnection = DatabaseUtil.CreateSqlConnection())
using (var cmd = new SqlCommand(query, sqlConnection))
{
I also worry about an InitializeSqlCommand()
command function that accepts a query
string, but makes no provision for query parameters. Yes, you can still add parameters later in code, but in my experience this tends to encourage the use of string concatenation for parameter data... or more accurately, fails to adequately discourage it, which amounts to the same thing. You want to make sure you don't have SQL Injection vulnerabilities in the application. If you continue to use InitializeSqlCommand()
, I structure it more like this:
Public Function InitializeSqlCommand(cn As SqlConnection, query As String, ParamArray paramters() As SqlParamter) As SqlCommand
Dim result As SqlCommand = cn.CreateCommand()
result.CommandText = query
If parameters IsNot Nothing AndAlso parameter.Length > 0 Then
result.Parameters.AddRange(parameters)
End If
Return result
End Sub
It's not necessary to call sqlConnection.Close()
if the connection was created in a using
block. The same applies to the DataReader.
Finally, the typical pattern for the DataReader is not to check the HasRows
property. It's usually enough to only check the results of the Read()
method, and usually in a while
loop.
Put it all together, including the revised VB functions, like this:
var parameters = new SqlParameter[] { }; //define parameters here
using (var sqlConnection = DatabaseUtil.CreateSqlConnection())
using (var cmd = DatabaseUtil.InitializeSqlCommand(sqlConnection, query, parameters))
using (var reader = cmd.ExecuteReader())
{
while(reader.Read())
{
//some code here
}
}
you don't need the DatabaseUtil
. just do it like this:
using (var sqlConnection =new SqlConnection(connectionString)){
var cmd = new SqlCommand(query, sqlConnection);
sqlConnection.Open();
var reader = cmd.ExecuteReader();
while(reader.Read())
{
//do whatever you want
};
}
You don't need to close the connection, when you use using
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.