Шаблон проектирования C # для классов Database Helper - PullRequest
1 голос
/ 25 февраля 2011

Я разрабатываю Службу WCF, которая будет вызываться несколькими сотнями клиентов, и у меня возник вопрос о лучшей архитектуре для классов, которые будут выполняться запросами к базе данных. Сегодня я имею доступ только к SQL Server, поэтому у меня есть статический класс, который я вызываю внутри, который выполняет всю грязную работу по созданию соединений и устройств чтения данных. Ниже приведен простой пример:

namespace DBHelper.Utility
{
  public static class SqlDBManager
  {
    public static void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
    {
      String sConnectionString = GetConnectionStringFromConfig(pConnStringConfigName);
      SqlConnection oConn = new SqlConnectionsConnectionString 
      oConn.Open();
      try
      {
        SqlCommand oCommand = new SqlCommand(pSql, oConn);
        oCommand.CommandTimeout = 0;
        if (pDBManagerParams != null)
        {
          foreach (SqlParameter sqlParam in pDBManagerParams)
          {
            oCommand.Parameters.Add(sqlParam);
          }
        }
        oCommand.ExecuteNonQuery();
      }
      finally
      {
        oConn.Close();
      }
    }
  }
}

Теперь мне нужно добавить поддержку для запуска как Sql Server, так и Oracle. Моя первоначальная идея состояла в том, чтобы объявить интерфейс и сделать так, чтобы мой существующий SqlDBManager реализовал его, а затем разработать OracleDBManager, реализующий тот же интерфейс. Проблема в том, что мой класс статический, а статические классы не могут реализовать интерфейс. Я хотел бы, чтобы мой вспомогательный класс оставался статичным, поскольку он намного более практичен, и мне не нужно создавать новый объект каждый раз, когда мне нужно выполнить запрос. Я также подумал об использовании наследования классов, но у меня не может быть виртуальных методов statis, поэтому я не пользуюсь ими. Я рассмотрел некоторые одноэлементные реализации, чтобы мне не пришлось создавать классы, но тогда у меня возникли бы проблемы с многопоточным доступом.
Какой будет лучший шаблон проектирования, чтобы я мог иметь высокую производительность в многопоточных сценариях (очень важно), не слишком много рабочего кода для повышения производительности (не нужно создавать много классов), и иметь стандартные методы для обоих OracleDBManager а SqlDBManager классы? Стандартный метод очень важен, потому что я не хочу, чтобы код, использующий эти вспомогательные классы, знал, подключены ли они к Oracle или Sql Server.
Я рассматривал возможность использования решения ORM, такого как Entity Framework 4 и nHibernate, но влияние на производительность было слишком сильным. Поскольку я буду выполнять простые запросы, разница в синтаксисе запросов между PL-SQL и TSQL не будет иметь значения.
Любой вклад и идея будет принята с благодарностью. Tks

Ответы [ 2 ]

2 голосов
/ 25 февраля 2011

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

Решение, которое я предлагаю, является многогранным. Сначала интерфейс с подписью, похожей на ту, что вы перечислили выше:

public Interface IDbManager {
     void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
}

Это может быть реализовано в версиях для SQL и Oracle, у вас уже есть версия SQL, просто сделайте ее нестатичной и реализуйте интерфейс.

Теперь попробуйте фабрику базы данных, например, как показано ниже:

public static class DbFactory {
    public static IDbManager CreateDb(DbType type) {
        select (type) {
            case DbType.Sql:
                return new SqlDbManager();
                break;
            case DbType.Sql:
                return new OracleDbManager();
                break;
        }
    }
}

Тогда вы сможете сделать что-то вроде:

var db = DbFactory.CreateDb(DbType.Sql);
db.RunQuery(...);

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

Надеюсь, это поможет!

2 голосов
/ 25 февраля 2011

Почему бы не сделать статический метод приватным , обернуть классы в интерфейсе для поддержки MS-SQL / Oracle и вызвать приватные статические методы в соответствующих интерфейсах?

Например:

public interface ISqlDbManager
{
   void SaveOrder(Order o);
   void FindOrderById(int orderId);
}

public class SqlServerDbManager : ISqlDbManager
{
    private static void RunSql(String pSql, DBParamsHelper pDBParams, String   pConnStringConfigName)
    {
       // implement as you did above
    }

   public void FindOrderById(int orderId)
   {
      // create SQL, call private "RunSql" method.
   }
}

Сделайте то же самое для другой реализации (OracleDbManager).

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

И это также упростит модульное тестирование - создайте класс «MockDbManager», где приватный статический метод выполняет базовые операции LINQ над списком в памяти.

Что касается примечания, настоятельно рекомендует использовать хранимые процедуры вместо создания команд sql вручную.Лучше для кэширования / оптимизации плана запросов.

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