Reputation: 196689
I have a website and I have a data access class that has an OdbcConnection. In the constructor I have this code:
public MySybaseProvider()
{
_conn = GetConn();
}
public OdbcConnection GetConn()
{
string connString = "DSN=SybaseIQ;Eng=SYSERVER;Links=tcpip(Host=" + _connectionInfo.Host + ";Port=" + _connectionInfo.Port + ");UID=" + _connectionInfo.User + ";PWD=" + _connectionInfo.Pwd + ";";
return new OdbcConnection(connString);
}
and through out the class i have the following code:
private OdbcQuery GetQuery(string sql)
{
return new OdbcQuery(_conn, sql);
}
I am trying to figure out the best way to make sure I close the connection properly. Should I implement IDisposable? should i open and close the connection on each query? Are there any other best practices here.
To clarify, my use case is that i am loading a single web page but it takes about 10 queries to get all of the data needed for the page.
Upvotes: 1
Views: 1624
Reputation: 329
So I have submitted another Answer Because I realised that I usually use Enterprise Library for my Data Access and not pure .net which changes things a bit. For one the DataAccessApplicationBlock (DAAB) takes care of opening and closing the Connection(s) to the Database so I don't have too, therefore I use it like below. Also in this case a easier and more effiecint way to do what is described is to execute all the SELECT Statements in 1 Stored Proc and Then Read through and Parse each result set one at a time.
Example:
Stored Proc
Create PROCEDURE [dbo].[GetUserByEmail]
@UserID int,
@AccountID int,
AS
BEGIN
SET NOCOUNT OFF;
SELECT * FROM Users WHERE UserID = @UserID and AccountID = @AccountID
SELECT * FROM UserAddresses WHERE UserID = @UserID
END
C# Code:
public class DataAccessLayer
{
private static DataAccessLayer me = new DataAccessLayer();
private DataAccessLayer() { }
public static DataAccessLayer GetInstance()
{
return me;
}
public Database GetDatabase(string connectionString, string provider)
{
DbProviderFactory providerFactory = DbProviderFactories.GetFactory(provider);
return new GenericDatabase(connectionString,
providerFactory);
}
}
public class Repository
{
protected Database curDatabase;
public Repository()
{
curDatabase = DataAccessLayer.GetInstance().GetDatabase("ConnectionString", "System.Data.Odbc");
}
public Database CurrentDatabase
{
get { return curDatabase; }
}
}
public class UserRepository : Repository
{
public User GetUser(int urserID, int accountID)
{
using (IDataReader dataReader = CurrentDatabase.ExecuteReader("StroedProcName", urserID, accountID))
{
//User Details
while (dataReader.Read())
{
//Parse Data
}
dataReader.NextResult();
//User Address(es)
while (dataReader.Read())
{
//Parse Data
}
}
}
}
Upvotes: 1
Reputation: 56497
Check if ODBC connection pooling is enabled, and create and open a connection object with the using
statement for each of your accesses to the database:
using (var conn = new OdbcConnection(_connString)) {
conn.Open();
// do a database command ...
}
(Note that I changed the design to store your _connString
in a field)
This is the most idiomatic way to do this, and you don't need to worry about creating your connection in the constructor, storing it in a field, or even implementing IDisposable
.
Upvotes: 1
Reputation: 2771
You can use the following pattern to ensure the connection is disposed. Even if an error occurs it will be disposed of. For safer coding you should use a connection string builder to build the connection. You should only create / use the connection when you are planning to perform an operation. It should NOT hang around for the life of your application. You can use the connection string / properties for that instead.
public OdbcConnection GetConn()
{
OdbcConnectionStringBuilder sb = new OdbcConnectionStringBuilder();
sb.Driver = "Microsoft Access Driver (*.mdb)";
sb.Add("Dbq", "C:\\info.mdb");
sb.Add("Uid", "Admin");
sb.Add("Pwd", "pass!word1");
OdbcConnection con = new OdbcConnection(sb.ConnectionString);
return con;
}
public void DoSomeWork()
{
using(OdbcConnection connection = GetConn())
{
// Do stuff with your connection here
}
}
Upvotes: 0
Reputation: 62057
I would argue you definitely should implement IDisposable
and follow the dispose pattern Keep in mind the garbage collector knows nothing about IDisposable
. You should as a last resort have a finalizer that will kill the DB connection if need be, but suppress the finalizer whenever possible (see the link I added for all the gory details).
As to whether you want to create a new connection per command or keep one around for the life of the object, that's much more subjective and depends on your scenario, environment, and many other things. I recommend exploring both and see what you think. If this is a "real" DB, perhaps talk to the DBA and see what they think.
Either way, implementing IDisposable
is your friend, as you can have nice, clean, well defined disposing code in a pattern that all .NET developers are familiar with.
Upvotes: 0