Строка подключения, полученная из одной БД для использования в библиотеке классов для доступа ко 2-й БД ... Предложения? - PullRequest
0 голосов
/ 04 мая 2018

Окружающая среда: .Net, SQL Server, WinForms Desktop

Контрольная база данных (дБ1) Базы данных клиентов (db2, db3, db4 и т. Д.)

Справочная информация: Каждому из наших клиентов нужна своя база данных. Это договорное обязательство из-за соответствия стандартам в определенных отраслях. Некоторые пользователи нашего приложения имеют доступ только к определенным базам данных.

Сценарий: Имя пользователя приложения передается в нашу управляющую базу данных (db1) из приложения при загрузке. Там есть поиск, который определяет, к какому клиенту этот пользователь имеет доступ, и возвращает информацию о строке подключения для подключения к базе данных определенного клиента (db2 или db3 или db4 или т. Д.), Которая будет использоваться в течение всего времени выполнения. Вся моя бизнес-логика находится в DAL, как и должно быть, в библиотеке классов .Net.

Предложения по наилучшему способу / способам получения информации строки подключения в DAL БЕЗ передачи в каждый конструктор / метод, который вызывается в DAL.

Я придумала одно возможное решение, но хочу выбрать свой мозг, чтобы посмотреть, есть ли другой или лучший способ.

Возможные решения:

  • Глобальный модуль в DAL, имеющий открытые поля, такие как "dbServer" и "dbName". Установите их, а затем используйте DAL по мере необходимости. Их нужно будет устанавливать каждый раз, когда DAL используется во всем приложении, но, по крайней мере, мне не нужно делать подпись каждого отдельного конструктора, а метод требует информацию о строке подключения.

  • Файл настроек (предпочтительно XML), в который приложение записывает после получения информации о соединении и чтения DAL в течение всего времени выполнения.

Мысли и / или предложения? Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Создайте ConnectionStringProvider класс, который предоставит вам строку подключения

    public class ConnectionStringProvider 
    {
         // store it statically so that every instance of connectionstringprovider 
         //   uses the same value        
        private static string _customerConnectionString;

        public string GetCustomerConnectionString()
        {
            return _customerConnectionString;
        }

        public void SetCustomerConnectionString(string connectionString)
        {
            _customerConnectionString = connectionString;
        }
    }

Использование ConnectionStringProvider в вашем DAL

    public class MyCustomerDAL
    {
        private ConnectionStringProvider _connectionStringProvider;

        public MyCustomerDAL()
        {
            _connectionStringProvider = new ConnectionStringProvider();
        }

        public void UpdateSomeData(object data)
        {
            using (var con = new SqlConnection(
                  connectionString: _connectionStringProvider.GetCustomerConnectionString()))
            {
                //do something awesome with the connection and data
            }
        }
    }

Установка / изменение строки подключения

    new ConnectionStringProvider()
        .SetCustomerConnectionString(connString);

Примечание Причина, по которой я решил использовать метод вместо свойства get / set в ConnectionStringProvider, заключается в том, что, возможно, в будущем вы решите читать / записывать их из файла, и хотя вы можете читать / писать из файла в свойстве, которое вводит в заблуждение вашего потребителя. кто думает, что свойство будет простым хитом без производительности. Использование функции говорит вашему потребителю о возможном падении производительности, поэтому используйте ее с умом.

Небольшая абстракция для юнит-тестирования

Вот небольшой вариант, который позволит вам абстрагироваться для модульного тестирования (и в конечном итоге IoC)

    public class MyCustomerDAL
    {
        private IConnectionStringProvider _connectionStringProvider;

        public MyCustomerDAL()
        {
            //since not using IoC, here you have to explicitly new it up
            _connectionStringProvider = new ConnectionStringProvider();
        }

        //i know you don't want constructor, i included this to demonstrate how you'd override for writing tests
        public MyCustomerDAL(IConnectionStringProvider connectionStringProvider)
        {
            _connectionStringProvider = connectionStringProvider;
        }

        public void UpdateSomeData(object data)
        {
            using (var con = new SqlConnection(
             connectionString: _connectionStringProvider.GetCustomerConnectionString()))
            {
                //do something awesome with the connection and data
            }
        }
    }

    // this interface lives either in a separate abstraction/contracts library
    //     or it could live inside of you DAL library
    public interface IConnectionStringProvider
    {
        string GetCustomerConnectionString();
        void SetCustomerConnectionString(string connectionString);
    }

    public class ConnectionStringProvider : IConnectionStringProvider
    {
        // store it statically so that every instance of connectionstringprovider uses the same value
        private static string _customerConnectionString;

        public string GetCustomerConnectionString()
        {
            return _customerConnectionString;
        }

        public void SetCustomerConnectionString(string connectionString)
        {
            _customerConnectionString = connectionString;
        }
    }

Приложение A - Использование IoC и DI

Отказ от ответственности: цель следующей части о IoC не в том, чтобы сказать, что один путь является правильным или неправильным, а просто в том, чтобы выдвинуть идею как другой способ решения проблемы.

В этой конкретной ситуации внедрение зависимостей сделает решение задачи очень простым; особенно если вы использовали контейнер IoC в сочетании с инжектором конструктора.

Я не имею в виду, что это сделало бы код более простым, оно было бы более или менее одинаковым, это сделало бы умственную сторону "как мне легко получить некоторую услугу в каждом классе DAL?" простой ответ; введите его .

Я знаю, что вы сказали, что не хотите менять конструктор. Это круто, вы не хотите менять это, потому что это - боль - поменять все места реализации.

Однако, если бы все создавалось IoC, вы бы не заботились о добавлении в конструкторы, потому что никогда не вызывали бы их напрямую.

Затем вы можете добавить такие службы, как ваш новый IConnectionStringProvider, прямо в конструктор и покончить с этим.

0 голосов
/ 04 мая 2018

Такая установка может помочь. Если вы идете по пути IoC, вы можете удалить параметризованный конструктор и сделать объект Connection тоже зависимым. Тем не менее, вам нужно будет вставить ваш поставщик внедрения зависимостей в код, поскольку строка подключения поступает из базы данных.

   public class User
    {
        public string ConnectionString
        {
            get; set;
        }
    }

    public class SomeBusinessEntity
    {

    }

    public class CallerClass
    {
        public IBaseDataAccess<SomeBusinessEntity> DataAccess
        {
            get;
            set;
        }

        public void DoSomethingWithDatabase(User user)// Or any other way to access current user
        {
            // Either have specific data access initialized 
            SpecificDataAccess<SomeBusinessEntity> specificDataAccess = new SpecificDataAccess<SomeBusinessEntity>(user.ConnectionString);
            // continue

            // have dependency injection here as well. Your IoC configuration must ensure that it does not kick in until we get user object
            DataAccess.SomeMethod();
        }
    }

    public interface IBaseDataAccess<T>
    {
        IDbConnection Connection
        {
            get;
        }

        void SomeMethod();

        // Other common stuff
    }

    public abstract class BaseDataAccess<T> : IBaseDataAccess<T>
    {
        private string _connectionString;
        public BaseDataAccess(string connectionString)
        {
            _connectionString = connectionString;
        }

        public virtual IDbConnection Connection
        {
            get
            {
                return new SqlConnection(_connectionString);
            }
        }

        public abstract void SomeMethod();

        // Other common stuff

    }

    public class SpecificDataAccess<T> : BaseDataAccess<T>
    {
        public SpecificDataAccess(string connectionString) : base(connectionString)
        {
        }

        public override void SomeMethod()
        {
            throw new NotImplementedException();
        }

        public void SomeSpecificMethod()
        {
            using (Connection)
            {
                // Do something here
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...