【问题标题】:How to return IQueryable<T> for further querying如何返回 IQueryable<T> 以进行进一步查询
【发布时间】:2013-05-08 17:57:16
【问题描述】:

我正在从这里尝试 PagedList.Mvc 库

https://github.com/TroyGoode/PagedList

有这个用法示例

var products = MyProductDataSource.FindAllProducts(); //returns IQueryable<Product> representing an unknown number of products. a thousand maybe?

        var pageNumber = page ?? 1; // if no page was specified in the querystring, default to the first page (1)
        var onePageOfProducts = products.ToPagedList(pageNumber, 25); // will only contain 25 products max because of the pageSize

MyProductDataSource.FindAllProducts() 的典型实现;符合

public IQuerable<T> MyProductDataSource.FindAllProducts()
{
   using ( var ctx = new MyCtx() )
   {
       return ctx.MyList().Where( .... );
   }
}

其中当然有 InvalidOperationException() 和 DBContext 已被处理的消息

寻找关于如何返回 IQueryable 的最佳实践,可以在这里毫无问题地使用?

【问题讨论】:

  • 这不是典型的实现。通常,您将上下文注入到存储库类中,这意味着您不会在方法级别进行处理。
  • @WiktorZychla 我不同意。两者都是有用的实现。当可以将上下文范围限定为方法时,这是可以接受的事情,但是当查询的生成超出该方法的范围时,这不是一个选项,在这种情况下,您需要调整上下文的范围,例如也就是说,无论它在哪里,它都包含该查询的生命周期。程序员应该能够理解任何给定查询的生命周期,并确定上下文的范围,使其处于同一“级别”,不多也不少。
  • @Servy: true 但在大多数情况下,您的上下文生命周期是“per-http-context”。请注意,他用 asp.net 标记了这个问题。您所说的是一般理论,他需要针对他的特定 asp.net 场景的精确指导。
  • @WiktorZychla 生命周期将比“per-http-context”少一些,所以如果你在那个级别上限定你的上下文,它不太可能太窄。也就是说,在范围太广的范围内界定上下文也可能会出现问题(它将消耗更多资源并持续更长时间)。只要有可能,您应该确保上下文的生命周期与查询的生命周期完全相同,或者只是稍微大一点,而不是始终将上下文的范围限定在您知道远远超出其需要的级别。当然,如果性能不是问题...

标签: c# .net asp.net-mvc visual-studio asp.net-mvc-4


【解决方案1】:

最好的做法是通过使用 IoC 容器将 DbContext 的生命周期保持为 每个 HTTP 请求,大多数 IoC 容器都支持 HttpRequest 生命周期。

因此您可以利用 DbContext 的范围,它允许您在上层使用 IQueryable

我喜欢哪两个 IoC 容器的更多信息:autofacninject

autofac 如何在here 中支持 MVC

或者NInjecthere中如何支持MVC

如果您是 IoC 容器的新手,建议您看看 Martin Flower 的 dependency injection 的基本概念。然后继续使用您选择的 IoC 容器之一。

但是,您需要非常小心如何使用IQueryable 以及应该停止支持它的层。如果没有,后面的魔鬼,从实体框架延迟加载会降低性能。我的一条规则是不支持查看 IQueryable

【讨论】:

    【解决方案2】:

    您需要“向上移动”数据上下文的范围:

    public IQueryable<T> MyProductDataSource.FindAllProducts(MyCtx context)
    {
        return context.MyList().Where( .... );
    }
    

    然后在更大的范围内创建上下文:

    using (var ctx = new MyCtx())
    {
        var products = MyProductDataSource.FindAllProducts(ctx);
    
        var pageNumber = page ?? 1;
        var onePageOfProducts = products.ToPagedList(pageNumber, 25);
    }
    

    【讨论】:

    • 另一种方法是将上下文注入数据源,而不是注入数据源的每个方法。
    • @WiktorZychla 关键是上下文的生命周期需要增加以超过查询的生命周期,您需要多高才能实现这一目标当然会因查询而异。它可能需要在该对象的范围内,也可能不在。
    • 我认为应该是 IQueryable
    猜你喜欢
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多