2009-08-21 2 views
11

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

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

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

+2

Предлагаю вам разбить код на разные блоки

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

ответ

2

для текущей потребности, я согласен с NHibernate ...

Сразу хочу отметить, что-то с вашей иерархии классов ...

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

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

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

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

+0

Мне понравился этот подход – Kalpak

1

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

10

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

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

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

+0

Даже 1% сомнений? – MusiGenesis

+0

Так как сомнение <машина эпсилон, нет. – Juliet

0

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

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

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

1

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

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

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

0

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

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

0

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

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

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

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

2

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

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter; 

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

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

2

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

Смежные вопросы