Skip to content

Commit

Permalink
Breaking change note on DbSet not implement IAsyncEnumerable
Browse files Browse the repository at this point in the history
Closes #3101
  • Loading branch information
roji committed Oct 1, 2021
1 parent 60e5eda commit 76da1c7
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
10 changes: 5 additions & 5 deletions entity-framework/core/miscellaneous/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Asynchronous Programming - EF Core
description: Querying and saving data asynchronously with Entity Framework Core
author: roji
ms.date: 9/2/2020
ms.date: 10/1/2021
uid: core/miscellaneous/async
---
# Asynchronous Programming
Expand All @@ -26,19 +26,19 @@ For more information, see [the general C# asynchronous programming docs](/dotnet
## Async LINQ operators

In order to support executing LINQ queries asynchronously, EF Core provides a set of async extension methods which execute the query and return results. These counterparts to the standard, synchronous LINQ operators include ToListAsync, SingleAsync, AsAsyncEnumerable, etc.:
In order to support executing LINQ queries asynchronously, EF Core provides a set of async extension methods which execute the query and return results. These counterparts to the standard, synchronous LINQ operators include <xref:Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync%2A>, <xref:Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.SingleAsync%2A>, <xref:Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsAsyncEnumerable%2A>, etc.:

[!code-csharp[Main](../../../samples/core/Miscellaneous/Async/Program.cs#ToListAsync)]

Note that there are no async versions of some LINQ operators such as Where or OrderBy, because these only build up the LINQ expression tree and don't cause the query to be executed in the database. Only operators which cause query execution have async counterparts.
Note that there are no async versions of some LINQ operators such as <xref:System.Linq.Queryable.Where%2A> or <xref:System.Linq.Queryable.OrderBy%2A>, because these only build up the LINQ expression tree and don't cause the query to be executed in the database. Only operators which cause query execution have async counterparts.

> [!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.
## Client-side async LINQ operators

The async LINQ operators discussed above can only be used on EF queries - you cannot use them with client-side LINQ to Objects query. To perform client-side async LINQ operations outside of EF, use the [System.Linq.Async package](https://www.nuget.org/packages/System.Linq.Async); this package can be especially useful for performing operations on the client that cannot be translated for evaluation at the server.
The async LINQ operators discussed above can only be used on EF queries - you cannot use them with client-side LINQ to Objects query. To perform client-side async LINQ operations outside of EF, use the [`System.Linq.Async` package](https://www.nuget.org/packages/System.Linq.Async); this package can be especially useful for performing operations on the client that cannot be translated for evaluation at the server.

Unfortunately, referencing System.Interactive.Async causes ambiguous invocation compilation errors on LINQ operators applied to EF's DbSets; this makes it hard to use both EF and System.Interactive.Async in the same project. To work around this issue, add AsQueryable to your DbSet:
In EF Core 6.0 and lower, referencing `System.Linq.Async` unfortunately causes ambiguous invocation compilation errors on LINQ operators applied to EF's DbSets; this makes it hard to use both EF and `System.Linq.Async` in the same project. To work around this issue, add <xref:System.Linq.Queryable.AsQueryable%2A> to your DbSet:

[!code-csharp[Main](../../../samples/core/Miscellaneous/AsyncWithSystemInteractive/Program.cs#SystemInteractiveAsync)]
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Breaking changes in EF Core 6.0 - EF Core
description: Complete list of breaking changes introduced in Entity Framework Core 6.0
author: ajcvickers
ms.date: 08/10/2021
ms.date: 10/1/2021
uid: core/what-is-new/ef-core-6.0/breaking-changes
---

Expand All @@ -16,6 +16,7 @@ The following API and behavior changes have the potential to break existing appl
|:--------------------------------------------------------------------------------------------------------------------------------------|------------|
| [Cleaned up mapping between DeleteBehavior and ON DELETE values](#on-delete) | Low |
| [Removed last ORDER BY when joining for collections](#last-order-by) | Low |
| [DbSet no longer implements IAsyncEnumerable](#dbset-iasyncenumerable) | Low |

## Low-impact changes

Expand Down Expand Up @@ -103,3 +104,27 @@ Every ORDER BY imposes additional work at the database side, and the last orderi
#### Mitigations

If your application expects joined entities to be returned in a particular order, make that explicit by adding a LINQ `OrderBy` operator to your query.

<a name="dbset-iasyncenumerable"></a>

### DbSet no longer implements IAsyncEnumerable

[Tracking Issue #24041](https://github.com/dotnet/efcore/issues/24041)

#### Old behavior

<xref:Microsoft.EntityFrameworkCore.DbSet%601>, which is used to execute queries on DbContext, used to implement <xref:System.Collections.Generic.IAsyncEnumerable%601>.

#### New behavior

<xref:Microsoft.EntityFrameworkCore.DbSet%601> no longer directly implements <xref:System.Collections.Generic.IAsyncEnumerable%601>.

#### Why

<xref:Microsoft.EntityFrameworkCore.DbSet%601> was originally made to implement <xref:System.Collections.Generic.IAsyncEnumerable%601> mainly in order to allow direct enumeration on it via the `foreach` construct. Unfortunately, when a project also references [System.Linq.Async](https://www.nuget.org/packages/System.Linq.Async) in order to compose async LINQ operators client-side, this resulted in an ambiguous invocation error between the operators defined over `IQueryable<T>` and those defined over `IAsyncEnumerable<T>`. C# 9 added [extension `GetEnumerator` support for `foreach` loops](/dotnet/csharp/language-reference/proposals/csharp-9.0/extension-getenumerator), removing the original main reason to reference `IAsyncEnumerable`.

The vast majority of `DbSet` usages will continue to work as-is, since they either compose LINQ operators over `DbSet`, enumerate it directly, etc. The only usages broken are those which attempt to cast `DbSet` directly to `IAsyncEnumerable`.

#### Mitigations

If you need to refer to a <xref:Microsoft.EntityFrameworkCore.DbSet%601> as an <xref:System.Collections.Generic.IAsyncEnumerable%601>, call <xref:Microsoft.EntityFrameworkCore.DbSet%601.AsAsyncEnumerable%2A?displayProperty=nameWithType> to explicitly cast it.

0 comments on commit 76da1c7

Please sign in to comment.