Каков наилучший способ поддержки нескольких баз данных для продукта .NET? - PullRequest
11 голосов
/ 21 августа 2009

Мы разрабатываем продукт, который может поддерживать несколько баз данных. Сейчас мы делаем что-то подобное, чтобы наш код поддерживал как MS SQL, так и MySQL:

namespace Handlers
{
    public class BaseHandler
    {
        protected string connectionString;
        protected string providerName;

        protected BaseHandler()
        {
            connectionString = ApplicationConstants.DatabaseVariables.GetConnectionString();
            providerName = ApplicationConstants.DatabaseVariables.GetProviderName();
        }
    }
}

namespace Constants
{
    internal class ApplicationConstants
    {
        public class DatabaseVariables
        {
            public static readonly string SqlServerProvider = "System.Data.SqlClient";
            public static readonly string MySqlProvider = "MySql.Data.MySqlClient";

            public static string GetConnectionString()
            {
                return ConfigurationManager.ConnectionStrings["CONNECTION_STRING"].ConnectionString; 
            }

            public static string GetProviderName()
            {
                return ConfigurationManager.ConnectionStrings["CONNECTION_STRING"].ProviderName;
            }
        }
    }
}

namespace Handlers
{
    internal class InfoHandler : BaseHandler
    {
        public InfoHandler() : base()
        {
        }

        public void Insert(InfoModel infoModel)
        {
            CommonUtilities commonUtilities = new CommonUtilities();
            string cmdInsert = InfoQueryHelper.InsertQuery(providerName);
            DbCommand cmd = null;
            try
            {
                DbProviderFactory provider = DbProviderFactories.GetFactory(providerName);
                DbConnection con = LicDbConnectionScope.Current.GetOpenConnection(provider, connectionString);
                cmd = commonUtilities.GetCommand(provider, con, cmdInsert);
                commonUtilities.PrepareCommand(cmd, infoModel.AccessKey, "paramAccessKey", DbType.String, false, provider, providerName);
                commonUtilities.PrepareCommand(cmd, infoModel.AccessValue, "paramAccessValue", DbType.String, false, provider, providerName);
                cmd.ExecuteNonQuery();
            }
            catch (SqlException dbException)
            {
                //-2146232060 for MS SQL Server
                //-2147467259 for MY SQL Server
                /*Check if Sql server instance is running or not*/
                if (dbException.ErrorCode == -2146232060 || dbException.ErrorCode == -2147467259)
                {
                    throw new BusinessException("ER0008");
                }
                else
                {
                    throw new BusinessException("GENERIC_EXCEPTION_ERROR");
                }
            }
            catch (Exception generalException)
            {
                throw generalException;
            }
            finally
            {
                cmd.Dispose();
            }
        }
    }
}

namespace QueryHelpers
{
    internal class InfoQueryHelper
    {
        public static string InsertQuery(string providerName)
        {
            if (providerName == ApplicationConstants.DatabaseVariables.SqlServerProvider)
            {
                return @"INSERT INTO table1
           (ACCESS_KEY
           ,ACCESS_VALUE)
     VALUES
           (@paramAccessKey
           ,@paramAccessValue) ";
            }
            else if (providerName == ApplicationConstants.DatabaseVariables.MySqlProvider)
            {
                return @"INSERT INTO table1
           (ACCESS_KEY
           ,ACCESS_VALUE)
     VALUES
           (?paramAccessKey
           ,?paramAccessValue) ";
            }
            else
            {
                return string.Empty;
            }
        }
    }
}

Подскажите, пожалуйста, есть ли лучший способ сделать это? Также каковы плюсы и минусы подхода?

Ответы [ 10 ]

10 голосов
/ 21 августа 2009

Что бы вы ни делали, не пишите свой собственный код отображения. Это уже было сделано раньше, и, вероятно, это было сделано в миллион раз лучше, чем то, что вы могли написать вручную.

Без сомнения, вы должны использовать NHibernate . Это объектно-реляционный картограф, который делает доступ к базе данных прозрачным: вы определяете набор классов DAL, которые представляют каждую таблицу в вашей базе данных, и используете поставщиков NHibernate для выполнения запросов к вашей базе данных. NHibernate будет динамически генерировать SQL, необходимый для запроса базы данных и заполнения ваших объектов DAL.

Приятной особенностью NHibernate является то, что он генерирует SQL на основе того, что вы указали в файле конфигурации. Из коробки он поддерживает SQL Server, Oracle, MySQL, Firebird, PostGres и несколько других баз данных .

5 голосов
/ 21 августа 2009

Я бы использовал NHibernate .

Вот хороший учебник для начинающих

2 голосов
/ 22 августа 2009

Для вашей текущей необходимости я согласен с NHibernate ...

Просто хочу кое-что указать на вашу иерархию классов ...

Вам лучше использовать интерфейс

Как (Просто проверьте документ или Интернет для точного синтаксиса)

Interface IDBParser  
    Function1  
    Function2  

class MSSQLParser : IDBParser  
    Function1  
    Function2  

class MySQLParser : IDBParser  
    Function1  
    Function2 

Тогда в вашем коде вы можете использовать интерфейс

Main()  
    IDBParser dbParser;  
    if(...)  
       dbParser = new MSSQLParser();  
    else  
       dbParser = new MySQLParser();  

    SomeFunction( dbParser );  

// the parser can be sent by parameter, global setting, central module, ...  
    SomeFunction( IDBParser dbParser)  
      dbParser.Function1();  

Таким образом, вам будет легче управлять, и ваш код не будет заполнен тем же условием if / else. Также будет намного проще добавлять другие БД. Еще одним преимуществом является то, что он может помочь вам с модульным тестированием, отправив фиктивный объект.

2 голосов
/ 21 августа 2009

Если вам нужно сопоставить записи базы данных с объектами, я предлагаю вам воспользоваться решением, которое уже было предложено: NHibernate. Если это кажется излишним для вашего приложения, и вы хотите использовать подход Ado.net и не нуждаетесь в O / RM-soultion, вам следует посмотреть, что сделали ребята из Spring.net, и узнать о Абстракция провайдера Ado.Net.

2 голосов
/ 21 августа 2009

Если вам нужно кодировать его самостоятельно и не использовать продукт, который предоставляет унифицированный доступ, помните, что такие объекты, как SqlDataAdapter и OracleDataAdapter наследуются от общего DbDataAdapter (по крайней мере, в более поздних версиях среды выполнения). Если вы преобразуетесь в DbDataAdapter, вы можете написать код, который будет работать с обеими базами данных в тех местах, где вы будете делать то же самое для обеих баз данных. Часть вашего кода будет выглядеть примерно так:

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter;

После того, как вы завершили тестирование, не имеет значения, является ли это SqlDataAdapter или OracleDataAdapter. Вы можете назвать это так же.

Однако помните, что кодирование для двух баз данных означает использование функций, которые существуют только в обеих, при этом нужно обходить недостатки обеих. Это не очень хорошая идея.

1 голос
/ 21 августа 2009

В таких случаях всегда хорошо создавать многоуровневую архитектуру, в которой все, что связано с БД, просто на уровне доступа к данным. Тогда у вас могут быть разные реализации уровня DAO, одна для Oracle, SQL Server и т. Д. *

Вы должны отделить бизнес-уровень от уровня DAO с помощью интерфейсов, чтобы ваш бизнес-уровень просто использовал их для доступа к уровню DAO. Таким образом, вы могли бы полностью заменить базовую реализацию уровня DAO для работы на БД Oracle или любой другой системе, которая вам нравится.

Еще одно хорошее предложение - взглянуть на объектно-реляционные картографы, как Скотт уже предлагал. Я бы посмотрел на NHibernate или Entity Framework.

1 голос
/ 21 августа 2009

Существуют слои объектно-реляционного отображения, которые будут поддерживать несколько технологий баз данных, например Пространства сущностей .

0 голосов
/ 21 августа 2009

Многие люди предложили структуру отображения O / R, такую ​​как NHibernate. Это вполне разумный подход, если вы по какой-то причине не хотите использовать O / R mapper. Что-то вроде NHibernate, вероятно, даст вам 95% + пути, но вам может потребоваться написать собственный SQL. Не паникуйте, если это так; Вы все еще можете сделать специальное решение для остальных.

В этом случае возьмите биты, для которых действительно нужен пользовательский SQL, и выделите их в модуль плагина для конкретной платформы. Напишите плагины Oracle, MySQL, SQL Server (и т. Д.) По мере необходимости для отдельных платформ баз данных, которые вы хотите поддерживать.

ADO.Net упрощает упаковку sprocs, поэтому вы можете переместить зависимый от платформы уровень в некоторые хранимые процедуры, предоставляя более или менее согласованный API для среднего уровня. По-прежнему существуют некоторые зависимости от платформы (например, префикс «@» в именах переменных SQL Server), поэтому вам необходимо создать универсальный механизм обертки sproc (что не так уж сложно).

Если повезет, определенные операции, которые вам понадобятся , чтобы выполнить их таким образом, будут довольно малы, поэтому объем работ по обслуживанию плагинов будет ограничен.

0 голосов
/ 21 августа 2009

Прямо сейчас у Microsoft Entity Framework есть несколько недостатков, некоторые из которых могут стать препятствиями в зависимости от предполагаемой архитектуры приложения.

Из того, что я видел и читал о V2, который будет поставляться с .Net 4, я думаю, что он, безусловно, заслуживает того, чтобы на него посмотрели.

0 голосов
/ 21 августа 2009

Один из подходов к этой проблеме - спроектировать ваше приложение так, чтобы оно полностью работало с отключенными наборами данных, и напишите компонент доступа к данным, который будет обрабатывать выборку данных из разных марок баз данных, которые вы будете поддерживать, а также постоянные изменения, внесенные в наборы данных. приложением вернуться к исходным базам данных.

Плюсы: DataSets в .Net хорошо написаны, просты в использовании и мощны, и отлично справляются с предоставлением методов и инструментов для работы с данными на основе таблиц.

Минусы: этот метод может быть проблематичным, если вашему приложению нужно работать с очень большими наборами данных на стороне клиента.

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