如何一次初始化基类属性,而不是从所有派生类中传递基类属性?

时间:2019-07-04 07:19:28

标签: c# .net ado.net refactoring

我有一个小型图书馆,在其中执行1个长时间运行的操作,并根据该操作在数据库表中保存一些数据。现在这是一个小型图书馆,其中不包含很多数据库表操作,因此我使用了Ado .net来管理数据访问层。

我创建了基类,并在其中放置了连接字符串和Ado.net命令执行。

我有3-4个类,其中某些方法执行插入,更新和删除,但是问题是,每当我创建此类的对象时,我都必须将连接字符串传递给这4个类。

代码:

 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);
        }
    }

如您所见,我这里有4个类,并且必须从每个此类中将连接字符串传递给基类:

1)VariantRepo

2)RegionRepo

3)CategoryRepo(未显示,但与上面的2相同)

4)TestRepo(未显示,但与上面的2相同)。

所以我想在这里解决两件事:

1)可以设计基类的方式是,我只需要传递一次连接字符串,而不必传递4个具体类中的每一个?

2)我想将此隐藏在某些类后面的脏逻辑(Sql parameter creation code)下,以提高可读性,因为我必须在很多地方这样做:

List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@TestId", TestId));
parameters.Add(new SqlParameter("@VariantId", VariantId));

我认为将基类作为具体类,但比将基类作为抽象类更有意义,我想这就是为什么我将基类标记为抽象。

有人可以帮我设计更好的方法吗?

2 个答案:

答案 0 :(得分:0)

这可能不是您要查找的答案,但是我将使用配置文件,将其存储在connstring中,然后在基类中将其设置为静态变量。

答案 1 :(得分:0)

您明确要求的内容是不可能的。每个派生类都必须使用其ctor进行初始化,因此每个ctor必须以一种或另一种方式引入连接字符串。 您可以:

  • 使用一个工厂类,该类在其ctor中获取一次连接字符串,然后返回使用该连接字符串初始化的repo对象,如
class RepoFactory
{
    private readonly string _connectionString;

    public RepoFactory(string connectionString)
    {
        _connectionString = connectionString;
    }

    public VariantRepo GetVariantRepo(int testId, int variantId) => 
        new VariantRepo(_connectionString, testId, variantId);

    ...
}
  • 在整个代码中使用依赖注入,创建一个ConnectionStringProvider类或类似的类,该类将具有仅获取属性ConnectionString(可能从配置文件中读取该值),然后将其注入您的各种存储库。