You bring up several issues, and the code you are showing us brings up some more. Things you may want to think about:
Try to keep the database centric activities constrained into their own classes. No one else needs to know about how to return a list of rows for the GlobalStats
object other than the actual class that handles pulling that data out of the database and making it into an actual object for you. No one. If anyone else does know, then your class is not using information hiding (which since we're in an object oriented language, you should be).
If the object implements IDisposable
, then you should be wrapping it with a try {} finally {}
block, or even better, wrap it with a using
statement (see my second example below).
Your connection string should only be accessible to the classes that actually need it (part of separating your concerns). Perhaps having a base DataAccess class that has that information?
public abstract class DataAccess
{
protected const string ConnectionString = "YourConnectionStringHere";
}
Then your repositories can inherit from this class, and you don't have a global static constant that causes your code to be unnecessarily coupled.
Here's how I'd write what you're writing (be careful, this code isn't really meant to be used, it's for illustrative purposes only):
[WebMethod]
public List<GlobalStat> GetStats()
{
GlobalStatsRepository repository = new GlobalStatsRepository();
List<GlobalStat> stats = repository.GetStats();
return stats;
}
DataAccessLayer
public class GlobalStatsRepository
{
public List<GlobalStat> GetStats()
{
string sql = @"SELECT * from GlobalStats"; //no, not a good practice
var stats = new List<GlobalStat>();
try
{
string ConString = Constants.connString;
conn = new SqlConnection(ConString);
cmd = new SqlCommand(sql, conn);
conn.Open();
dr = cmd.ExecuteReader();
while (dr.Read())
{
GlobalStat stat = new GlobalStat();
stat.Key = dr[0].ToString();
stat.Value = int.Parse(dr[1].ToString());
stats.Add(stat);
}
}
catch (SQLDataReaderException ex)
{
logger.Log(ex);
throw;
}
return stats;
}
}
Example of Parameritized Query
public List<GlobalStat> GetStatsById(int id)
{
var stats = new List<GlobalStat>();
string sql = @"SELECT * from GlobalStats WHERE Id = @Id";
using (SqlConnection conn = new SqlConnection(ConString))
{
conn.Open();
using (SQLCommand command = new SqlCommand(sql, conn))
{
command.Parameters.Add(new SqlParameter("Id", id));
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
GlobalStat stat = new GlobalStat();
stat.Key = dr[0].ToString();
stat.Value = int.Parse(dr[1].ToString());
stats.Add(stat);
}
}
}
return stats;
}