防止重复的DB调用,因为面向对象的方法在MVC3应用程序

本文关键字:面向对象的 因为 方法 应用程序 MVC3 调用 DB | 更新日期: 2023-09-27 18:18:37

我们有一个MVC3应用程序,我们已经创建了许多小的操作和视图来处理在我们需要的地方放置数据。例如,如果它是一个博客,我们想要显示评论,我们有一个评论操作和视图,我们可以把它放在我们想要的任何地方,一个用户资料视图,和博客文章视图,等等。

这导致的问题是每个小视图或操作都需要调用,通常是对同一个服务,每次页面加载多次,因为我们的应用程序中有所有其他小视图。因此,在包含这些小视图的非常大的页面上,我们可能有80多个sql调用,其中40%是重复的,然后页面变慢。当前的解决方案是缓存一些数据,并在ViewBag中传递一些数据,如果我们可以,所以如果你想要一个用户的个人资料,你检查它是否缓存或ViewBag,如果它不是请求它。

对于设计模式来说,这感觉真的很脏,而且viewbag方法看起来很糟糕,因为它必须从上到下传递。我们在HttpCurrent中添加了一些数据。项,使它每一个请求(而不是缓存,因为数据可以改变),但必须有一些干净的解决方案,感觉不对,是干净的?

编辑

我被要求更具体,因为这是一个内部业务应用程序,我不能透露太多细节。

用软件来类比。让我们将其与facebook进行比较。想象一下,这个MVC应用程序对每个facebook帖子都有一个操作,然后在该操作下,它有另一个操作用于"喜欢"按钮和评论数量,然后另一个操作用于向用户显示最热门的评论。我们的应用程序的设计方式,我们将获得当前用户配置文件在每个操作(因此像4次在上述情况下最少),然后子操作将获得父墙帖子,以验证你有权限看到它。现在你可以考虑缓存对每个安全检查、墙贴等的调用,但我觉得缓存是针对应用生命周期中需要的东西,而不仅仅是为了纠正应用架构中的错误而在这里和那里做的小块。

防止重复的DB调用,因为面向对象的方法在MVC3应用程序

您是否能够将任何@Html.Action()调用替换为@Html.Partial()调用,传递模型数据而不是依赖于操作方法从db中获取数据?

您可以创建包含其他ViewModels作为属性的CompositeViewModel。例如,它可能包含一个UserViewModel属性、一个BlogPostViewModel属性和一个Collection<BlogComment>属性。

在返回容器/主视图的action方法中,您可以优化数据访问。听起来你已经通过服务抽象了很多可重复的代码,但是你没有发布任何代码,所以我不确定这种方法会有多DRY。

但是,如果您可以做到这一点,而无需从子操作中重复许多代码,那么您可以在主视图中使用@Html.Partial("~/Path/to/view.cshtml", Model.UserViewModel),并将子操作方法保留给其他没有如此繁重负载的页面。

根据我对你的问题的理解,我看到了两个可能对你的代码有所帮助的地方。

  1. 您每页呼叫太多。换句话说,你的工作分工太细了。您可以通过创建包含更多信息的对象来组合对服务的调用。如果您有一个comments对象和一个具有关于注释的聚合数据的对象,可以将它们合并到一个对象/一个调用中。

  2. 缓存更有效。您说您已经在尝试缓存数据,但需要一种更好的方法来实现这一点。在我最近参与的一个项目中,我使用AOP框架对WCF调用进行缓存。它的开发效果很好,但最终在一个流量很大的网站中速度太慢了。

WCF调用的代码大致如下:

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

您只需在WCF调用上放置一个带有时间间隔的装饰器,AOP就会处理剩下的缓存工作。当然,我们也使用了一个外部缓存框架(AppFabric)来存储WCF调用的结果。

面向方面框架(AOP): http://en.wikipedia.org/wiki/Aspect-oriented_programming我们在AOP中使用了Unity:企业库Unity vs其他IoC容器

我强烈建议尝试缓存实际的服务调用,这样你就可以随心所欲地调用它们。

最好的方法是创建一个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
        }
    }

问题是:如果您执行查询80次,那么您将访问db 80次。放置请求作用域的缓存是最好的解决方案。实现它的最优雅的方式是通过AOP,所以你的代码不介意这个问题。