Какой самый эффективный способ подключения к базе данных? - PullRequest
3 голосов
/ 30 ноября 2011

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

У нас есть разные способы доступа к системе.

Вариант № 1: Создает базу данных с кодом ниже.

using Microsoft.Practices.EnterpriseLibrary.Data;

namespace Ivans.Healthcare.CommercialAccess.Data
{
    public abstract class DataAccess : DataHelperBase
    {
        public const int commandTimeout = 7200;
        private static Database m_db = null;
        public StringBuilder Status {get; set;}

        public DataAccess()
        {
            this.Status = new StringBuilder();

            if (m_db == null)
            {
                bool bIfRunsOnWebService = false;
                try
                {
                    if (DynamicConfigurationManager.AppSettings["WebService"] != null)
                    {
                        bIfRunsOnWebService = true;
                    }
                }
                catch {}

                if (!bIfRunsOnWebService)
                {
                    m_db = DatabaseFactory.CreateDatabase(DataAccessResource.IDS_DB_ALIAS);
                }
                else
                {
                    m_db = CreateDatabase(DataAccessResource.IDS_WS_DB_ALIAS);
                }
            }
        }

Тогда каждый раз, когда нужно вызвать хранимую процедуру, метод будет содержать что-то вроде этого:

public IEnumerable<InquiryServiceType> GetActive(bool is5010)
{

    Database db = getDB();
    DbCommand dbCmd = db.GetStoredProcCommand(DataAccessResource.IDS_SP_SEL_InquiryServiceTypeData_ListServiceTypes);
    db.AddInParameter(dbCmd, DataAccessResource.IDS_SP_SEL_InquiryServiceTypeData_ListServiceTypes_Is5010Request, DbType.Boolean, is5010);

    DataSet ds = new DataSet();
    db.LoadDataSet(dbCmd, ds, new string[] { DataAccessResource.IDS_TBL_InquiryServiceTypeData });

    return DataSetTranslator.TranslateInquiryServiceTypeDataSet(ds);
}

Вариант 2

Эта опция немного более модульная и пыталась создать общий метод базы данных.

    private Database currentDB;
private const int commandTimeout = 7200;

public DataAccess(Common.Enums.ConnectionString currentConnection)
{
    currentDB = DatabaseFactory.CreateDatabase(currentConnection.ToDescription());
}

public IEnumerable<T> SelectMany<T>(string spName, params Param[] parameters) where T : IDataPopulate<T>, new()
{
    var storedProcedure = CreateStoredProcedureCommand(spName);
    AddParameters(storedProcedure, parameters);

    IDataReader myReader = null;
    IList<T> listOfItems = new List<T>();

    try
    {
        myReader = currentDB.ExecuteReader(storedProcedure);
        if (myReader == null)
        {
            return listOfItems;
        }

        while (myReader.Read())
        {
            listOfItems.Add(new T().FillObject(myReader));
        }

        return listOfItems;
    }
    catch (Exception ex)
    {
        string message = string.Format("Error Message: {0}\r\nStored Procedure: {1}\r\n", ex.ToString(), spName);
        throw new Exception(message);
    }
    finally
    {
        DataAccessDisposal.DataReader(myReader);
        DataAccessDisposal.StoredProcedure(storedProcedure);
    }
}

Тогда вызов базы данных будет выглядеть так:

public IEnumerable<InquiryServiceTypes> GetAll(int payerID)
{
    Param payerIdParam = new Param("@payerID", DbType.Int32, payerID);
    return dataAccess.SelectMany<InquiryServiceTypes>("dbo.proc_PayersInquiryServiceTypesSel", payerIdParam);
}

Заключение

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

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

Спасибо, C

Ответы [ 3 ]

5 голосов
/ 30 ноября 2011

Я бы сказал просто: есть абстракции, которые уже делают это (и делают это очень хорошо). Если вы можете справиться с созданием соединения, то, например, с помощью dapper-dot-net :

return connection.Query<InquiryServiceTypes>(
        "dbo.proc_PayersInquiryServiceTypesSel",
        new { payerId }, commandType: CommandType.StoredProcedure);

, который запишет всю параметризацию и материализацию для вас в сильно кэшированном IL. Не нужно писать сложный метод Fill или метод заполнения и очень-очень быстро (идентично производительности написания всего кода читателя ADO.NET вручную, но без скучного кода и шансов на опечатки).

Написание всех этих Fill методов вручную не эффективно (для времени разработчика).

Примечание в вышеприведенном; анонимный тип определяет параметры, то есть он говорит, что «существует параметр int с именем payerId, с тем же значением, которое было передано в». Вы также можете иметь:

new { id = payerId, name = "abc", allData = true }

, который добавил бы @id (int) со значением из payerId, @name (nvarchar) со значением 'abc' и @allData (бит) со значением 1.


Редактировать точки в комментариях:

  • пул соединений является ортогональным, поскольку по умолчанию это выполняется автоматически (с сервером SQL), если вы быстро освобождаете свои соединения
  • entlib добавляет, IMO, накладные расходы без веской причины. Код, говорящий с entlib, практически идентичен общению с необработанным ado.net, за исключением случаев, когда речь идет о большем раздутии и косвенном обращении. Я бы избегал entlib, если вы на самом деле не используете то, что оно делает, чтобы облегчить вашу жизнь
  • загрузка набора данных всегда накладные расходы; DataTable и т. Д. Сложны - гораздо сложнее, чем загрузка модели POCO. Загрузка набора данных просто , чтобы вы могли затем использовать набор данных для загрузки объектной модели, неэффективно и создает ненужный мусор в куче, которую нужно собрать, и в любом случае имеет много шагов (адаптеры и т. Д.), все это занимает время
  • подход DataTable также требует полного чтения таблицы, а не буферизации без буферизации (возможно с необработанным блоком чтения и блока итератора); это может быть важно, если у вас очень большие результаты
  • из двух представленных подходов, второй вариант IMO гораздо предпочтительнее, но я не , как интерфейс; это плохое «разделение интересов» - задача POCO - представлять объект домена, а не знать о базе данных
  • Как отмечалось выше, есть варианты, аналогичные второму варианту, которые намного меньше работают для реализации / сопровождения и не вызывают проблем с SoC; Я бы посмотрел на это с большим интересом
  • такие опции также предназначены для более сложных сценариев; несколько сеток; горизонтальные объединения (в подобъекты); и т.д.
0 голосов
/ 30 ноября 2011

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

См. http://msdn.microsoft.com/en-us/library/ms978388.aspx для сравнения производительности методов доступа к данным.

Советую вам взглянуть на использование Entity Framework, Massive или PetaPoco, так как использование одной из этих платформ, скорее всего, сэкономит ваше время, а также сделает код более читабельным / поддерживаемым.

0 голосов
/ 30 ноября 2011

Лично я считаю, что код Dot net, т.е. код приложения, никоим образом не должен быть связан с базой данных. Причины:

  1. Если созданный выше метод предназначен для SQL Server, то вы ограничены в использовании SQL Server. Вы должны иметь возможность легко переключать хранилище.

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

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

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