Как инициализировать свойство базового класса один раз вместо передачи его из всех производных классов? - PullRequest
1 голос
/ 04 июля 2019

У меня есть небольшая библиотека, в которой я выполняю 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).

Итак, есть 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 голосов
/ 04 июля 2019

То, что вы явно просите, невозможно. Каждый производный класс должен быть инициализирован с использованием своего ctor, поэтому каждый ctor должен так или иначе принимать строку подключения. Вы могли бы:

  • Используйте фабричный класс, который принимает строку соединения в своем ctor один раз, а затем возвращает объекты репо, инициализированные этой строкой соединения, как в
class RepoFactory
{
    private readonly string _connectionString;

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

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

    ...
}
  • Используйте Dependency Injection по всему коду, создайте класс ConnectionStringProvider или аналогичный, который будет иметь свойство «только для получения» ConnectionString (возможно, прочитайте это значение из файла конфигурации), а затем внедрите его в свои различные репозитории.
0 голосов
/ 04 июля 2019

Вероятно, это не тот ответ, который вы ищете, но я бы использовал файл конфигурации, в котором я бы сохранил connstring, а затем установил бы его как статическую переменную в базовом классе.

...