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 3, 2019
1 parent bb82f4a commit 1a85f8e
Show file tree
Hide file tree
Showing 12 changed files with 337 additions and 122 deletions.
8 changes: 4 additions & 4 deletions entity-framework/core/querying/async.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: Asynchronous Queries - EF Core
author: rowanmiller
ms.date: 01/24/2017
author: smitpatel
ms.date: 10/01/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. 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#](/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.
Expand All @@ -18,4 +18,4 @@ Entity Framework Core provides a set of asynchronous extension methods that can
> [!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.

81 changes: 37 additions & 44 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/01/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.
In order to evaluate query on server as much as possible, Entity Framework Core converts parts of the query which can be evaluated on client side to convert them to parameters and 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 cannot be translated to server, EF Core will fetch required data from server and evaluate it on client. If EF Core detects expression which cannot 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 cannot be translated to server.

> [!TIP]
> You can view this article's [sample](https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/Querying) on GitHub.
> [!NOTE]
> Prior to version 3.0, Entity Framework Core supported parts of query to be evaluated on client anywhere in the query. See the [previous versions section](#previous-versions) for more details.
## Client evaluation

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?highlight=6)] -->
``` csharp
var blogs = context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(blog => new
{
Id = blog.BlogId,
Url = StandardizeUrl(blog.Url)
})
.ToList();
```
> [!TIP]
> You can view this article's [sample](https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/Querying) on GitHub.
<!-- [!code-csharp[Main](samples/core/Querying/ClientEval/Sample.cs)] -->
``` csharp
public static string StandardizeUrl(string url)
{
url = url.ToLower();
In the following example a helper method is used to standardize URLs for blogs which 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.

if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
[!code-csharp[Main](../../../samples/core/Querying/ClientEval/Sample.cs#ClientProjection)]

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

## Client evaluation performance issues
## Unsupported 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.
While client evaluation can be very useful, in some instances it can result in poor performance. Consider the following query, in which the helper method is now used in a where filter. Because this can't be performed in the database, all the data needs to be pulled into memory and then the filter needs to be applied on the client. Depending on the amount of data on the server, and how much of that data is filtered out, this could result in poor performance. Hence Entity Framework Core blocks such client evaluation and throws a runtime exception.

<!-- [!code-csharp[Main](samples/core/Querying/ClientEval/Sample.cs)] -->
``` csharp
var blogs = context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToList();
```
[!code-csharp[Main](../../../samples/core/Querying/ClientEval/Sample.cs#ClientWhere)]

## Explicit client evaluation

In certain instances user may need to force into client evaluation explicitly like following cases

- Data is small so that doing evaluation on client does not 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 `AsAsyncEnumerable` for async).

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

## Potential memory leak in client evaluation

Since query translation and compilation is expensive, by default, EF Core caches compiled query plan. With client evaluation allowed in the top projection, the cached delegate can use client code. In most cases, EF Core generates parameters for client parts of the tree so that their values can be replaced when reusing the query plan. But with certain constants in expression tree, it cannot be converted to parameters. If the client code contains such constants then those objects cannot be garbage collected. If such object contains DbContext or other services inside it then it could cause memory usage of the app to grow over time. In order to avoid potential memory leak, EF Core throws exception whenever it encounter constants of type which cannot be mapped in 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 does not 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 arguments which can be mapped by database provider based on components being used in the method body.
- **Other constants**: If constant is encountered in any other case then you can evaluate if constant is really needed in processing. If it is necessary to have that constant or if you cannot 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 is applicable to EF Core versions prior to 3.0.

## Optional behavior: throw an exception for client evaluation
EF Core supported client evaluation in any part query hence queries similar to one posted in [Unsupported client evaluation](#unsupported-client-evaluation) section worked correctly but it caused performance issue without users noticing. In order to notify users that query was being evaluated on client, EF Core logged client evaluation warning. See [Logging](xref:core/miscellaneous/logging) for more information on viewing logging output.

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 performing client evaluation except for projection (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 are 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 1a85f8e

Please sign in to comment.