Предотвращение повторных вызовов БД из-за объектно-ориентированного подхода в приложении MVC3 - PullRequest
5 голосов
/ 21 декабря 2011

У нас есть приложение MVC3, в котором мы создали множество небольших действий и представлений для размещения данных там, где нам нужно. Например, если это был блог, и мы хотели показать комментарии, у нас есть действие и просмотр комментария, и мы можем разместить его там, где мы хотим, просмотр профиля пользователя, просмотр блога и т. Д.

Проблема, которую это вызвало, заключается в том, что каждое маленькое представление или действие должно совершать вызов, обычно одной и той же службе, несколько раз за загрузку страницы из-за всех других небольших представлений, которые мы имеем в нашем приложении. Таким образом, на очень большой странице, содержащей эти маленькие представления, мы могли бы иметь более 80 вызовов sql, причем 40% из них были дубликатами, и тогда страница замедлялась. Текущее решение состоит в том, чтобы кэшировать некоторые данные и передавать некоторые данные в ViewBag, если мы можем, поэтому, если вы хотите, чтобы он был похож на профиль пользователя, вы проверяете, есть ли его кэш или ViewBag, если он не запрашивает его.

Это кажется действительно очень грязным для шаблона проектирования, и подход к пакету просмотра кажется ужасным, поскольку его нужно передавать сверху вниз. Мы добавили некоторые данные в HttpCurrent.Items, чтобы сделать их по запросу (вместо кэширования, поскольку эти данные могут измениться), но должно быть какое-то чистое решение, которое не кажется неправильным и тоже чистым?

EDIT

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

Итак, приведем это к аналогии с программным обеспечением. Давайте сравним это с фейсбуком. Представьте, что у этого MVC-приложения есть действие для каждой записи в Facebook, затем под этим действием есть еще одно действие для кнопки «Нравится» и количества комментариев, а затем еще одно действие для показа пользователю самых популярных комментариев. При разработке нашего приложения мы будем получать профиль текущего пользователя в каждом действии (например, как минимум 4 раза в описанной выше ситуации), а затем дочернее действие получит сообщение родительской стены, чтобы убедиться, что у вас есть разрешение на его просмотр. Теперь вы можете рассмотреть возможность кэширования вызовов для каждой проверки безопасности, записи на стене и т. Д., Но я чувствую, что кэширование предназначено для вещей, которые понадобятся в течение всего жизненного цикла приложения, а не только для маленьких кусочков, чтобы исправить ошибку в том, как Приложение спроектировано.

Ответы [ 4 ]

2 голосов
/ 22 декабря 2011

Можете ли вы заменить любой из ваших вызовов @ Html.Action () на вызовы @ Html.Partial (), передавая данные модели вместо того, чтобы полагаться на метод действия, чтобы получить их из БД?

Вы можете создать CompositeViewModel, который будет содержать другие ваши ViewModels в качестве свойств. Например, он может содержать свойство UserViewModel, свойство BlogPostViewModel и свойство Collection<BlogComment>.

В вашем методе действий, который возвращает контейнер / главное представление, вы можете оптимизировать доступ к данным. Похоже, у вас уже есть много повторяемого кода, абстрагируемого через службу, но вы не опубликовали никакого кода, поэтому я не уверен, насколько СУЩЕСТВЕННЫМ будет такой подход.

Но если вы можете сделать это, не повторяя lot кода из ваших дочерних действий, вы можете затем использовать @Html.Partial("~/Path/to/view.cshtml", Model.UserViewModel) в своем главном представлении и сохранить дочерний метод действия для других страниц, которые не такой тяжелый груз

0 голосов
/ 24 декабря 2011

Дело в том, что если вы выполняете запрос 80 раз, значит, вы нажимаете 80 раз.Размещение кэша в области запросов является лучшим решением.Самый элегантный способ его реализации - через АОП, поэтому ваш код не заботится об этой проблеме.

0 голосов
/ 21 декабря 2011

Лучше всего создать ActionFilter, который создаст и разрушит ваш метод персистентности. Это обеспечит ограничение самой дорогой части доступа к данным (т. Е. Создание соединения) один раз на запрос.

public class SqlConnectionActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var sessionController = filterContext.Controller;

            if (filterContext.IsChildAction)
                return;

            //Create your SqlConnection here
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.IsChildAction)
                return;

            //Commit transaction & Teardown SqlConnection
        }
    }
0 голосов
/ 21 декабря 2011

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

  1. У вас слишком много вызовов на страницу.Другими словами, ваше разделение работы слишком гранулировано.Возможно, вы сможете комбинировать вызовы к вашему сервису, создавая объекты, которые содержат больше информации.Если у вас есть объект комментариев и объект, в котором собраны данные о комментариях, возможно, объедините их в один объект / один вызов.Просто мысль.

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

Код будет выглядеть примерно так для вызова WCF (примерно):

[Caching(300)]
Comment GetComment(int commentId);

Вы бы просто поместили декоратор в вызов WCF с интервалом времени, и AOP позаботится обо всем остальном, вплоть до кэширования.Конечно, мы также использовали внешнюю инфраструктуру кэширования (AppFabric) для хранения результатов вызовов WCF.

Аспектно-ориентированная структура (AOP): http://en.wikipedia.org/wiki/Aspect-oriented_programming Мы использовали Unity для AOP: Enterprise LibraryUnity против других IoC-контейнеров

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

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