1

Can AsEnumerable() be removed from GetCars, and GetCars is still a deferred execution?

public IEnumerable<Car> GetCars(string id)
{

  IEnumerable<Car>  cars = IDocumentClient.CreateDocumentQuery<Car>(link).AsEnumerable();

 return cars.Where(r => r.Id == Id);

 }

Like below:

//GetCars2 is still deferred execution?
public IEnumerable<Car> GetCars2(string Id)
{

     IOrderedQueryable<Car>  cars = IDocumentClient.CreateDocumentQuery<Car>(link)

     return cars.Where(r => r.Id == .Id);

 }

https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.client.documentclient.createdocumentquery?view=azure-dotnet

Update

I want all the filterings to be done in database first, thus reduce data returned.

Also, I have more filtering after calling GetCar(). Using IEnumerable allows deferred execution for filtering inside and outside of GetCar().

Can IQueryable be used instead? What is the benefit?

Is the filtering in GetCars3 ALSO considered for SQL query (both GetCar2 and GetCar3)? Thus, both method reduce data returned from database?

 public IEnumerable<Car> GetCars3(string Model )
    {
       return GetCars2(id).Where(r => r.Model == Model);
     }

Update2

As mjwills suggests to use IQueryable as return type of GetCarX(). But I don't understand why. Because using IEnumerable<> still has all the benefits. That is, filetering is performed on database side, not C#. Please correct me if I am wrong.

Returning IEnumerable<T> vs. IQueryable<T>

LINQ provider:

https://azure.microsoft.com/en-us/blog/azure-documentdb-s-linq-provider-just-got-better/

Read query: How to construct IQueryable query using Linq when I just need count without reading all documents in Document-Db database?

https://github.com/Azure/azure-cosmos-dotnet-v2/issues/58

How to construct IQueryable query using Linq when I just need count without reading all documents in Document-Db database?

SQL: https://learn.microsoft.com/en-gb/azure/cosmos-db/sql-query-getting-started#linq-to-documentdb-sql

Update 3

This question is related to AsEnumerable(), which is used within the same function that Where is defined, as an example of don't it.

It has a subtle difference from previous posts, which is better explicitly explained on this post.

Thus, this post should not be marked as duplicate.

Pingpong
  • 7,681
  • 21
  • 83
  • 209
  • Adding `AsEnumerable` doesn't make it "immediate execution". It just means subsequent filtering etc will be client side (i.e. in C#). As a general rule, if it is `IQueryable` then try and leave it `IQueryable` as long as possible. – mjwills Jul 26 '19 at 22:30
  • But `CreateDocumentQuery(link)` doesn't send out query before calling 'AsEnumerable()', I think. – Pingpong Jul 26 '19 at 22:31
  • I want all the filtering to be done in database first, thus reduce data returned. – Pingpong Jul 26 '19 at 22:34
  • Using `AsEnumerable` is almost certainly not giving you anything useful. I'd suggest using `IQueryable`. If `GetCars` returns an `IQueryable` then further filtering is possible (and it can occur server-side, not in C# (if you use `AsEnumerable` it will be C# filtering after downloading all of the records)). – mjwills Jul 26 '19 at 22:37
  • Please see update 3 for re-opening the post. – Pingpong Jul 27 '19 at 15:58
  • I don't understand the edit. But I'll say it one more time. **If `Where` is called on an `IEnumerable` (e.g. after `AsEnumerable`) then the filtering is done client side**. There is no debate on this issue - this is how extension methods and `IEnumerable` works. You've explicitly said you want filtering to be server-side. `as an example of don't it.` It is unclear what this is referring to. `which is better explicitly explained on this post.` It is unclear what this is referring to. – mjwills Jul 28 '19 at 07:06
  • The **only** reason you should use `AsEnumerable` is if the code results in `Query expression is invalid, expression return type SomeTypeHere is unsupported. Query must evaluate to IEnumerable` exception, like at https://stackoverflow.com/questions/26719457/azure-documentdb-error-query-must-evaluate-to-ienumerable . In that situation **and only in that situation** should you use `AsEnumerable`. Otherwise **do not use it** and use `IQueryable` rather than `IEnumerable`. – mjwills Jul 28 '19 at 07:10

1 Answers1

3

In both of your examples, they will run using deferred execution - they won't send the underlying query to the server until the IQueryable or IEnumerable is iterated.

The difference between GetCars and GetCars2 is only that when the result of GetCars is eventually enumerated by its caller, the clause in the Where predicate will be run on the client - as each result in the iterable comes down from the server passes through, it will be evaluated and returned or discarded; versus in GetCars2 (if the specific implementation of IQueryable supports it) the Where predicate will be factored into the query that gets sent to the server. If the implementation of IQueryable returned from CreateDocumentQuery doesn't support method chaining to construct the query, then they'll both work the same way. But in either case, again, they both use deferred execution in that nothing will be sent to the server until the result of the method is actually enumerated.

Responding to the update added to the question - think of AsEnumerable() as a gate function. It cuts off communication between the IQueryable that is going to talk to the server and whatever other LINQ-type methods you add after it. The IQueryable is blind to what happens after AsEnumerable. So if you want to compose a server-side query using method chaining, don't interrupt the chain with AsEnumerable.

Rex M
  • 142,167
  • 33
  • 283
  • 313