如何返回IQueryable<T>以供进一步查询

5
我正在尝试使用此处提供的 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时不会出现问题?


这不是典型的实现方式。通常你会将上下文注入到仓储类中,这意味着你不会在方法级别处置。 - Wiktor Zychla
@WiktorZychla 我不同意。两种实现都很有用。当可以将上下文范围限定在方法内部时,这是可以接受的,但是当查询的生成超出该方法的范围时,这就不是一个选项了,在这种情况下,您需要调整上下文的范围,使其无论在哪里,都包含该查询的生命周期。程序员应该能够理解任何给定查询的生命周期,并将上下文范围限定在相同的“级别”,不多也不少。 - Servy
@Servy:没错,但在大多数情况下,您的上下文生命周期是“每个HTTP上下文”。请注意,他使用asp.net标记了问题。您所说的是一般理论的一部分,他需要针对他特定的asp.net场景的精确指导。 - Wiktor Zychla
@WiktorZychla 生命周期将会比“每个HTTP上下文”短一些,因此如果您将上下文范围限定在该级别,很少会太窄。尽管如此,将上下文范围限定得过于宽泛也可能会带来问题(它将消耗更多的资源更长时间)。只要可能,您应确保上下文的生命周期与查询的生命周期完全相同,或者仅略微大于查询的生命周期,而不是总是将上下文范围限定在您知道远远超出其需求的级别。当然,如果性能不是问题... - Servy
2个回答

4

在IT技术中,保持DbContext的生命周期为每个HTTP请求一致是一个好的实践,可以通过使用IoC容器实现,大多数IoC容器都支持HttpRequest生命周期。

因此,您可以利用DbContext的作用域,从而使上层可以使用IQueryable。

以下是我喜欢的两个IoC容器:autofac和ninject。

了解如何在autofac中支持MVC,请参见这里

或者了解如何在NInject中支持MVC,请参见这里

如果您对IoC容器不熟悉,建议您先了解Martin Flower的依赖注入的基本概念,然后选择其中一个IoC容器继续学习。

但是,您需要非常谨慎地使用IQueryable,并确定应该在哪个层级停止支持它。如果不小心,Entity Framework后面的“延迟加载”将会降低性能。我的一个规则是不要在View中支持IQueryable。


3

您需要“提升”数据上下文的范围:

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);
}

另一种选择是将上下文注入到数据源中,而不是注入到每个单独的方法中。 - Wiktor Zychla
@WiktorZychla 的意思是上下文的生命周期需要延长以超过查询的生命周期,为了实现这一点,你需要提高上下文的生命周期,具体需要多高当然取决于查询。它可能需要在该对象的范围内,也可能不需要。 - Servy
我认为应该是IQueryable<T>。 - Hugh Seagraves

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接