I have a small library where I am performing 1 long running operation and based on that operation,I am saving some data inside database tables.Now this is small library which does not include alot of database tables operation hence I have used Ado.net to manage data access layer.
I have created base class where I have put Connection string and Ado.net commands execution.
I have 3-4 class with some methods performing insert,update and delete but the problem is I have to pass connection string to each of this 4 class whenever I am creating the object of this class.
Code :
internal abstract class BaseRepo
{
private readonly string connectionString;
protected int TestId;
protected int VariantId;
public BaseRepo() { }
protected BaseRepo(string connection)
{
this.connectionString = connection;
}
internal virtual void ExecuteQuery(string query,
IList<SqlParameter> parameters)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(query, conn))
{
conn.Open();
foreach (SqlParameter parameter in parameters)
{
command.Parameters.Add(parameter);
}
command.ExecuteNonQuery();
}
}
}
internal virtual void ExecuteQueryWithTransaction(SqlConnection connection,SqlTransaction transaction, string query,
IList<SqlParameter> parameters)
{
using (SqlCommand command = new SqlCommand(query, connection, transaction))
{
foreach (SqlParameter parameter in parameters)
{
command.Parameters.Add(parameter);
}
command.ExecuteNonQuery();
}
}
internal virtual int ExecuteScalar(string query,
IList<SqlParameter> parameters)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(query, conn))
{
conn.Open();
foreach (SqlParameter parameter in parameters)
{
command.Parameters.Add(parameter);
}
var data = command.ExecuteScalar();
if (data == null)
return 0;
return (int)data;
}
}
}
}
internal class VariantRepo : BaseRepo
{
public VariantRepo(string connectionString,int testId,int variantId) : base(connectionString)
{
TestId = testId;
VariantId = variantId;
}
public VariantRepo(testId) : base(connectionString)
{
TestId = testId;
}
public void DeleteVariantData()
{
string query = "";
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@TestId", TestId));
parameters.Add(new SqlParameter("@VariantId", VariantId));
ExecuteQuery(query, parameters);
}
}
internal class RegionRepo : BaseRepo
{
public RegionRepo(string connectionString, int variantId) : base(connectionString)
{
VariantId = variantId;
}
public int GetRegionIdByVariantId()
{
string query = "";
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@id", VariantId));
return ExecuteScalar(query, parameters);
}
}
As you can see I have 4 class here and from each of this class I have to pass connection string to base class :
1) VariantRepo
2) RegionRepo
3) CategoryRepo
(not shown but it is same like above 2)
4) TestRepo
(not shown but it is same like above 2).
So there are 2 things that I would like to address here :
1) It is possible to design base class in a way that I have to pass connection string only once and not for each of the 4 concrete classes?
2) I want to hide this below dirty logic(Sql parameter creation code
) behind some class to have better readability because I have to do this at so many places:
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@TestId", TestId));
parameters.Add(new SqlParameter("@VariantId", VariantId));
I thought to have base class as concrete class but than having base class as abstract class makes more sense I guess that is why I have marked base class as abstract.
Can someone please help me to design this in better way?