从一个DB中检索的连接字符串,用于在类库中访问第二个DB ...建议?

时间:2018-05-04 12:18:34

标签: sql .net connection-string class-library

环境: .Net,SQL Server,WinForms Desktop

控制数据库(db1) 客户数据库(db2,db3,db4等)

背景 我们每个客户都需要自己的数据库。由于符合某些行业的标准,它是一项合同义务。我们应用程序的某些用户只能访问特定的数据库。

情境: 应用程序用户的用户名将从加载时的应用程序传递到我们的控制数据库(db1)。在那里进行查找,确定该用户有权访问的客户,并返回连接字符串信息,以便连接到确定客户的数据库(db2或db3或db4等),以便在运行时间内使用。我的所有业务逻辑都在一个DAL中,应该是在.Net类库中。

关于将连接字符串信息放入DAL的最佳方法/方法的建议,不要传递到DAL上调用的每个构造函数/方法。

我想出了一个可能的解决方案,但是想要挑选你的大脑,看看是否有另一种或更好的方法。

可能的解决方案:

  • DAL中的全局模块,具有公共字段,如" dbServer"和" dbName"。 设置它们然后根据需要使用DAL。每次在整个应用程序中使用DAL时都需要设置它们,但至少我不必使每个构造函数和方法的签名都需要连接字符串信息。

  • 应用程序在获取连接信息后写入的设置文件(最好是XML),DAL从运行时的生命周期开始读取。

想法和/或建议?提前谢谢。

2 个答案:

答案 0 :(得分:0)

这样的设置可能会有所帮助。如果您使用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
            }
        }
    }

答案 1 :(得分:0)

创建一个 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;
        }
    }

在DAL中使用 ConnectionStringProvider

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

注意 我选择在ConnectionStringProvider中使用方法而不是get / set属性的原因是因为将来您可能决定从文件中读取/写入这些属性,而您可以在属性中从文件读取/写入,这会误导您的消费者谁认为一个属性将是一个简单的性能减少。 使用函数告诉您的消费者可能会遇到一些性能问题,因此请明智地使用它。

进行单元测试的一点点算法

这是一个轻微的变化,使您能够抽象单元测试(最终是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等服务添加到构造函数中并完成它。