由于MVC3应用程序中面向对象的方法,防止重复的DB调用

时间:2011-12-21 17:53:42

标签: c# asp.net-mvc-3 design-patterns

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

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

对于设计模式来说,这真的很脏,并且viewbag方法似乎很糟糕,因为它必须从顶部向下传递。我们已经在HttpCurrent.Items中添加了一些数据,以便根据请求(而不是缓存,因为数据可以更改),但是必须有一些干净的解决方案,感觉不对,并且也是干净的?

修改

我被要求更具体,虽然这是一个内部业务应用程序,但我无法泄露大部分细节。

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

4 个答案:

答案 0 :(得分:2)

您是否可以使用@ Html.Partial()调用替换任何@ Html.Action()调用,传入模型数据而不是依赖于操作方法从数据库获取它?

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

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

但是,如果您可以在不重复子操作的批次代码的情况下执行此操作,则可以在主视图中使用@Html.Partial("~/Path/to/view.cshtml", Model.UserViewModel),并为其他页面保留子操作方法没有这么重的负担。

答案 1 :(得分:0)

根据我对您的问题的理解,我发现您的代码可能有两个可能的帮助。

  1. 每页有太多电话。换句话说,你的工作分工过于细化。您可以通过创建包含更多信息的对象来组合对服务的调用。如果您有一个注释对象和一个具有关于注释的聚合数据的对象,则可以将它们组合成一个对象/一个调用。只是一个想法。

  2. 更有效地缓存。你说你已经在尝试缓存数据了,但是想要一个更好的方法来做到这一点。在我最近的一个项目中,我使用AOP框架对WCF调用进行缓存。它非常适合开发,但在交通繁忙的网站上最终太慢了。

  3. 对于WCF调用(大致),代码会像这样出现:

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

    你只需要在一个时间间隔的WCF调用上放置一个装饰器,AOP就可以处理其余的缓存。当然,我们还使用外部缓存框架(AppFabric)来存储WCF调用的结果。

    面向方面的框架(AOP):http://en.wikipedia.org/wiki/Aspect-oriented_programming 我们使用Unity for AOP:Enterprise Library Unity vs Other IoC Containers

    我会强烈考虑尝试缓存实际的服务电话,以便您可以将它们称为心灵内容。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

问题是:如果您正在进行80次查询,那么您将在数据库中执行80次。放置请求范围的缓存是最佳解决方案。实现它的最优雅方式是通过AOP,因此您的代码不介意该问题。