Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return IQueryable<T> for further querying

I'm trying the PagedList.Mvc library from here

https://github.com/TroyGoode/PagedList

which has this usage sample

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

typical implmentations of MyProductDataSource.FindAllProducts(); are along the lines of

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

which of course has the InvalidOperationException() and DBContext is already disposed message

Looking for best practices on how to return IQueryable which can be used here without issues ?

like image 361
Kumar Avatar asked May 08 '13 17:05

Kumar


People also ask

Should I return IQueryable from repository?

If they add a where clause to a deferred IQueryable , you only have to send that data over the wire, not the entire result set. If you are using repository pattern - no, you should not return IQueryable.

What is IQueryable return?

IQueryable is executed. // // Returns: // A System.Type that represents the type of the element(s) that are returned when. // the expression tree associated with this object is executed.

What is the difference between returning IQueryable T vs IEnumerable T?

The major difference between IQueryable and IEnumerable is that IQueryable executes query with filters whereas IEnumerable executes the query first and then it filters the data based on conditions.

Is IQueryable faster than IEnumerable?

IQueryable is faster than IEnumerable. In addition to Munesh Sharma's answer:IEnumerable loads data in-memory and then apply filters to it one by one but IQueryable apply filters all at once and return the result.


2 Answers

The good practice is to keep the lifetime of DbContext as per HTTP request by using IoC container, most of IoC containers support HttpRequest lifetime.

So you can leverage the scope of DbContext which allows you to use IQueryable on upper layer.

More information which two IoC containers I like: autofac and ninject.

How autofac supports MVC in here

Or how NInject supports MVC in here

If you are new on IoC container, you would suggest you should take a look the basic concept of dependency injection from Martin Flower. Then go ahead with one of IoC container you choose.

But, you need to be very careful on how to use IQueryable and which layer you should stop support it. If not, the devil on behind, lazy loading from entity framework will slow down the performance. One of my rule is do not support IQueryable on View.

like image 103
cuongle Avatar answered Nov 05 '22 09:11

cuongle


You need to "move up" the scope of your data context:

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

Then create the context at the larger scope:

using (var ctx = new MyCtx())
{
    var products = MyProductDataSource.FindAllProducts(ctx);

    var pageNumber = page ?? 1;
    var onePageOfProducts = products.ToPagedList(pageNumber, 25);
}
like image 36
Servy Avatar answered Nov 05 '22 11:11

Servy