Skip to content

Commit

Permalink
Update Query documentation
Browse files Browse the repository at this point in the history
Resolves#615
Resolves#1636
Resolves#1648
Resolves#1699
Resolves#1777
  • Loading branch information
smitpatel committed Oct 4, 2019
1 parent 705e898 commit 44016f8
Show file tree
Hide file tree
Showing 15 changed files with 358 additions and 127 deletions.
10 changes: 10 additions & 0 deletions .openpublishing.redirection.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@
"source_path": "entity-framework/efcore-and-ef6/porting/ensure-requirements.md",
"redirect_url": "/ef/efcore-and-ef6/porting/index",
"redirect_document_id": false
},
{
"source_path": "entity-framework/core/querying/basic.md",
"redirect_url": "/ef/core/querying/index",
"redirect_document_id": false
},
{
"source_path": "entity-framework/core/querying/overview.md",
"redirect_url": "/ef/core/querying/how-query-works",
"redirect_document_id": false
}
]
}
12 changes: 6 additions & 6 deletions entity-framework/core/querying/async.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
---
title: Asynchronous Queries - EF Core
author: rowanmiller
ms.date: 01/24/2017
author: smitpatel
ms.date: 10/03/2019
ms.assetid: b6429b14-cba0-4af4-878f-b829777c89cb
uid: core/querying/async
---

# Asynchronous Queries

Asynchronous queries avoid blocking a thread while the query is executed in the database. This can be useful to avoid freezing the UI of a thick-client application. Asynchronous operations can also increase throughput in a web application, where the thread can be freed up to service other requests while the database operation completes. For more information, see [Asynchronous Programming in C#](https://docs.microsoft.com/dotnet/csharp/async).
Asynchronous queries avoid blocking a thread while the query is executed in the database. Async queries are important for keeping a responsive UI in thick-client applications. They can also increase throughput in web applications where they free up the thread to service other requests in web applications. For more information, see [Asynchronous Programming in C#](/dotnet/csharp/async).

> [!WARNING]
> EF Core does not support multiple parallel operations being run on the same context instance. You should always wait for an operation to complete before beginning the next operation. This is typically done by using the `await` keyword on each asynchronous operation.
> EF Core doesn't support multiple parallel operations being run on the same context instance. You should always wait for an operation to complete before beginning the next operation. This is typically done by using the `await` keyword on each async operation.
Entity Framework Core provides a set of asynchronous extension methods that can be used as an alternative to the LINQ methods that cause a query to be executed and results returned. Examples include `ToListAsync()`, `ToArrayAsync()`, `SingleAsync()`, etc. There are not async versions of LINQ operators such as `Where(...)`, `OrderBy(...)`, etc. because these methods only build up the LINQ expression tree and do not cause the query to be executed in the database.
Entity Framework Core provides a set of async extension methods similar to the LINQ methods, which execute a query and return results. Examples include `ToListAsync()`, `ToArrayAsync()`, `SingleAsync()`. There are no async versions of some LINQ operators such as `Where(...)`, `OrderBy(...)`, because these methods only build up the LINQ expression tree and don't cause the query to be executed in the database.

> [!IMPORTANT]
> The EF Core async extension methods are defined in the `Microsoft.EntityFrameworkCore` namespace. This namespace must be imported for the methods to be available.
[!code-csharp[Main](../../../samples/core/Querying/Async/Sample.cs#Sample)]
[!code-csharp[Main](../../../samples/core/Querying/Async/Sample.cs#ToListAsync)]
50 changes: 0 additions & 50 deletions entity-framework/core/querying/basic.md

This file was deleted.

79 changes: 36 additions & 43 deletions entity-framework/core/querying/client-eval.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,62 @@
---
title: Client vs. Server Evaluation - EF Core
author: rowanmiller
ms.date: 10/27/2016
author: smitpatel
ms.date: 10/03/2019
ms.assetid: 8b6697cc-7067-4dc2-8007-85d80503d123
uid: core/querying/client-eval
---
# Client vs. Server Evaluation

Entity Framework Core supports parts of the query being evaluated on the client and parts of it being pushed to the database. It is up to the database provider to determine which parts of the query will be evaluated in the database.
As a general rule, Entity Framework Core attempts to evaluate query on server as much as possible. EF Core converts parts of the query to parameters, which it can evaluate on client side. Rest of the query with generated parameters is given to database providers to determine what should be equivalent database query to do evaluation on the server. EF Core supports partial client evaluation in top-level projection (essentially, the last call to `Select()`). If parts of query in top-level projection can't be translated to server, EF Core will fetch required data from server and evaluate it on client. If EF Core detects expression, which can't be translated to server in any other place, then it throws runtime exception. See [how query works](xref:core/querying/how-query-works) to understand how EF Core determines what can't be translated to server.

> [!TIP]
> [!NOTE]
> Prior to version 3.0, Entity Framework Core supported client evaluation anywhere in the query. For more information, see the [previous versions section](#previous-versions).
## Client evaluation in top-level projection

> [!TIP]
> You can view this article's [sample](https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/Querying) on GitHub.
## Client evaluation
In the following example, a helper method is used to standardize URLs for blogs, which are returned from a SQL Server database. Since the SQL Server provider has no insight into how this method is implemented, it isn't possible to translate it into SQL. All other aspects of the query are evaluated in the database, but passing the returned `URL` through this method is done on the client.

In the following example a helper method is used to standardize URLs for blogs that are returned from a SQL Server database. Because the SQL Server provider has no insight into how this method is implemented, it is not possible to translate it into SQL. All other aspects of the query are evaluated in the database, but passing the returned `URL` through this method is performed on the client.
[!code-csharp[Main](../../../samples/core/Querying/ClientEval/Sample.cs#ClientProjection)]

<!-- [!code-csharp[Main](samples/core/Querying/ClientEval/Sample.cs?highlight=6)] -->
``` csharp
var blogs = context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(blog => new
{
Id = blog.BlogId,
Url = StandardizeUrl(blog.Url)
})
.ToList();
```
[!code-csharp[Main](../../../samples/core/Querying/ClientEval/Sample.cs#ClientMethod)]

<!-- [!code-csharp[Main](samples/core/Querying/ClientEval/Sample.cs)] -->
``` csharp
public static string StandardizeUrl(string url)
{
url = url.ToLower();
## Unsupported client evaluation

if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
While client evaluation is useful, it can result in poor performance sometimes. Consider the following query, in which the helper method is now used in a where filter. Because filter can't be applied in the database, all the data needs to be pulled into memory to apply filter on the client. Based on the amount of data on the server and the filter, client evaluation could result in poor performance. So Entity Framework Core blocks such client evaluation and throws a runtime exception.

return url;
}
```
[!code-csharp[Main](../../../samples/core/Querying/ClientEval/Sample.cs#ClientWhere)]

## Client evaluation performance issues
## Explicit client evaluation

While client evaluation can be very useful, in some instances it can result in poor performance. Consider the following query, where the helper method is now used in a filter. Because this can't be performed in the database, all the data is pulled into memory and then the filter is applied on the client. Depending on the amount of data, and how much of that data is filtered out, this could result in poor performance.
User may need to force into client evaluation explicitly in certain cases like following

<!-- [!code-csharp[Main](samples/core/Querying/ClientEval/Sample.cs)] -->
``` csharp
var blogs = context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToList();
```
- Data is small so that doing evaluation on client doesn't cause huge performance penalty.
- LINQ operator being used has no server-side translation.

In such cases, user can explicitly opt into client evaluation by calling methods like `AsEnumerable` or `ToList` (`AsAsyncEnumerable` or `ToListAsync` for async). By using `AsEnumerable` you would be streaming the results, but using `ToList` would cause buffering by creating the list, which also takes additional memory. Though if you're enumerating multiple times, then storing results in a list helps more since there's only one query to database. Depending on the particular usage, you should evaluate which method is more useful for the case.

[!code-csharp[Main](../../../samples/core/Querying/ClientEval/Sample.cs#ExplicitClientEval)]

## Potential memory leak in client evaluation

Since query translation and compilation are expensive, EF Core caches the compiled query plan. The cached delegate may use client code while doing client evaluation of top-level projection. EF Core generates parameters for client parts of the tree, to reuse the query plan by replacing parameter values. But certain constants in expression tree can be converted to parameters. If the cached delegate contains such constants, then those objects can't be garbage collected as they're still being referenced. If such object contains DbContext or other services inside it, then it could cause memory usage of the app to grow over time. It's generally sign of memory leak. EF Core throws exception whenever it comes across constants of type that can't be mapped using current database providers. Common causes and their solutions are as follows:

- **Using instance method**: When using instance methods in client projection, the expression tree contains constant of the instance. If your method doesn't use any data from instance, consider making the method static. If you need instance data in the method body, then pass specific data as an argument to the method.
- **Passing constant argument to method**: This case arises generally by using `this` in argument to client method. Consider splitting argument in to multiple scalar arguments, which can be mapped by database provider.
- **Other constants**: If constant is seen in any other case, then you can evaluate if constant is needed in processing. If it's necessary to have the constant or if you can't use solution to above cases, then create a local variable to store the value and use local variable in the query. EF Core will convert it to parameter.

## Client evaluation logging
## Previous versions

By default, EF Core will log a warning when client evaluation is performed. See [Logging](../miscellaneous/logging.md) for more information on viewing logging output.
The following section applies to EF Core versions before 3.0.

## Optional behavior: throw an exception for client evaluation
Older EF Core versions supported client evaluation in any part of query not just top-level projection. That's why queries similar to one posted under [Unsupported client evaluation](#unsupported-client-evaluation) section worked correctly. Since this behavior could cause unnoticed performance issue, EF Core logged client evaluation warning. For more information on viewing logging output, see [Logging](xref:core/miscellaneous/logging).

You can change the behavior when client evaluation occurs to either throw or do nothing. This is done when setting up the options for your context - typically in `DbContext.OnConfiguring`, or in `Startup.cs` if you are using ASP.NET Core.
Optionally EF Core allowed to change default behavior to throw exception or do nothing when doing client evaluation except for projection. The exception throwing would make it similar to the behavior in 3.0. To change the behavior, you need to configure warnings while setting up the options for your context - typically in `DbContext.OnConfiguring`, or in `Startup.cs` if you're using ASP.NET Core.

<!-- [!code-csharp[Main](samples/core/Querying/ClientEval/ThrowOnClientEval/BloggingContext.cs?highlight=5)] -->
``` csharp
```csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
Expand Down
Loading

0 comments on commit 44016f8

Please sign in to comment.