Ленивая загрузка в моем приложении C # - PullRequest
2 голосов
/ 12 августа 2009

У меня есть метод в моем DAL, возвращающий список клиентов:

Collection<Customer> FindAllCustomers();

У клиента есть следующие столбцы: ID, имя, адрес, биография

Мне нужно показать их в постраничной сетке в форме ASPX (show-Customers.aspx), где я буду показывать только эти столбцы: ID, Имя

Теперь, в моем DAL FindAllCustomers () я должен также вернуть поле Bio из SP (я заполняю коллекцию с помощью ридера)? Био поле может быть большим (nvarchar (max)). Я думал о ленивой загрузке или загрузке только обязательных полей. Но тогда в этом случае мне нужно будет создать другой метод, который возвращает «полный» список клиентов, включая биографию, чтобы сторонние приложения могли использовать его через сервисный уровень. Так что это нормально, чтобы создать такой метод:

Collection<Customer> FindAllCustomers(bool loadPartial);

Если loadPartial = true, то не загружайте Bio, иначе загрузите ее. В этом случае, поскольку я не хочу возвращать био из SP, мне нужно создать 2 оператора select в моем SP на основе значения bool.

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

Какие-либо предложения по наилучшему шаблону для реализации в таких случаях?

спасибо,

Викас

Ответы [ 8 ]

3 голосов
/ 19 января 2010

В этом случае я бы использовал enum, чтобы еще яснее понять значение параметра.

public enum RetrieveCustomerInfo
{
   WithBio,
   WithoutBio
}

А при вызове метода:

dao.FindAllCustomers(RetrieveCustomerInfo.WithBio);

Я не знаю, лучше ли это, но думаю, что это более понятно.

3 голосов
/ 12 августа 2009

Сторонняя вещь - это связка.

На первый взгляд, я обычно рекомендую, чтобы вы загружали только минимальные данные в обычном режиме, а затем загружали полную или дополнительную информацию по запросу (т. Е. Касание свойства может вызвать вызов БД - там может быть незначительное злоупотребление свойством) или фоном. основа процесса, в зависимости от характера того, что вы делаете.

Ленивый код свойства в порядке разъяснения:

class Customer
{
  private string _lazydata = null;

  public string LazyData
  {
    get
    {
      if (this._lazydata==null)
      {
        LazyPopulate();
      }
      return this._lazydata;
    }
  }

  private void LazyPopulate()
  {
    /* fetch data and set lazy fields */
  }
}

Будьте осторожны с этим, вы не хотите делать много вызовов БД, но при этом не хотите создавать узкое место, когда смотрите на что-то ленивое. Только природа вашего приложения может решить, подходит ли это.

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

Я бы пошел с:

Collection<Customer> FindAllCustomers()
{
  return this.FindAllCustomers(false);
}

Collection<Customer> FindAllCustomers(bool alldata)
{
  /* do work */
}
1 голос
/ 12 августа 2009

Почему бы не использовать ленивую загрузку в свойствах самого класса клиента? Дайте каждому свойству (Id, Name, Bio) частную переменную. В получателе каждого свойства, если частная переменная не равна нулю, возвращает ее, в противном случае считайте ее из вашего DAL.

Когда дело доходит до Bio, если вам нужно его лениво загрузить, то в своем геттере вы вызываете другой метод в классе Customer с именем LazyLoadAdditionalDetails () и вызываете там соответствующие sprocs, а затем возвращаете вашу личную переменную.

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

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

Я думаю, что хорошо иметь два метода, оптимизированных для конкретных случаев, если вы четко указали их имена. Лично я не думаю:

Collection<Customer> FindAllCustomers(bool loadPartial);

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

Проясни, и все хорошо.

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

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

В качестве примечания вам не обязательно использовать две хранимые процедуры или классический оператор if в вашей хранимой процедуре.

Вы можете использовать оператор case для NULL из поля, когда loadPartial == true.

Case WHEN @loadPartial = 1 THEN NULL ELSE [bio] END
1 голос
/ 12 августа 2009

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

Несколько вопросов ...

  • Этот параметр определяет только, загружена ли биография? Будут ли в будущем другие поля, которые не загружаются, если для него установлено значение true?
  • Что произойдет, если я попытаюсь получить доступ к Bio, если для loadPartial установлено значение true?

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

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

вместо

Collection<Customer> FindAllCustomers(bool loadPartial);

Я бы сделал это

Collection<Customer> FindAllCustomers(bool includeBio);

«loadPartial» не сообщает потребителю, что является «частичным» клиентом. Я также согласен с пунктами Аннакаты.

0 голосов
/ 12 августа 2009
class CustomerDAO
{
   private bool _LoadPartial = true;
   public bool LoadPartial
   {
      get
      {
         return _LoadPartial;
      }

      set
      {
         _LoadPartial = value;
      }
   }


   public Collection<Customer> FindAllCustomers()
   {
      ...
   }
}

Был бы другой вариант, хотя мне также нравится аннаката.

...