diff --git a/benchmark/EFCore.SqlServer.Benchmarks/EFCore.SqlServer.Benchmarks.csproj b/benchmark/EFCore.SqlServer.Benchmarks/EFCore.SqlServer.Benchmarks.csproj
index c8e2081f22a..c1884b89fd2 100644
--- a/benchmark/EFCore.SqlServer.Benchmarks/EFCore.SqlServer.Benchmarks.csproj
+++ b/benchmark/EFCore.SqlServer.Benchmarks/EFCore.SqlServer.Benchmarks.csproj
@@ -2,6 +2,7 @@
net461;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2;netcoreapp3.0
+ netcoreapp3.0
Microsoft.EntityFrameworkCore.Benchmarks
Exe
diff --git a/benchmark/EFCore.Sqlite.Benchmarks/EFCore.Sqlite.Benchmarks.csproj b/benchmark/EFCore.Sqlite.Benchmarks/EFCore.Sqlite.Benchmarks.csproj
index e5f227bdcf8..858477ef9c7 100644
--- a/benchmark/EFCore.Sqlite.Benchmarks/EFCore.Sqlite.Benchmarks.csproj
+++ b/benchmark/EFCore.Sqlite.Benchmarks/EFCore.Sqlite.Benchmarks.csproj
@@ -2,6 +2,7 @@
net461;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2;netcoreapp3.0
+ netcoreapp3.0
Microsoft.EntityFrameworkCore.Benchmarks
Exe
diff --git a/src/EFCore.Abstractions/EFCore.Abstractions.csproj b/src/EFCore.Abstractions/EFCore.Abstractions.csproj
index 9eaa6bdf25b..eac661300e4 100644
--- a/src/EFCore.Abstractions/EFCore.Abstractions.csproj
+++ b/src/EFCore.Abstractions/EFCore.Abstractions.csproj
@@ -2,7 +2,7 @@
Provides abstractions and attributes that are used to configure Entity Framework Core
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.Abstractions
Microsoft.EntityFrameworkCore
diff --git a/src/EFCore.Cosmos/EFCore.Cosmos.csproj b/src/EFCore.Cosmos/EFCore.Cosmos.csproj
index b0a0ad17f0d..44922d8609e 100644
--- a/src/EFCore.Cosmos/EFCore.Cosmos.csproj
+++ b/src/EFCore.Cosmos/EFCore.Cosmos.csproj
@@ -2,7 +2,7 @@
Azure Cosmos provider for Entity Framework Core.
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.Cosmos
Microsoft.EntityFrameworkCore.Cosmos
diff --git a/src/EFCore.Cosmos/Query/Expressions/Internal/QueryShaperExpression.cs b/src/EFCore.Cosmos/Query/Expressions/Internal/QueryShaperExpression.cs
index 5ee58ebba89..0dd2ed4701f 100644
--- a/src/EFCore.Cosmos/Query/Expressions/Internal/QueryShaperExpression.cs
+++ b/src/EFCore.Cosmos/Query/Expressions/Internal/QueryShaperExpression.cs
@@ -82,23 +82,28 @@ public AsyncShaperEnumerable(
_shaper = shaper;
}
- public IAsyncEnumerator GetEnumerator() => new AsyncShaperEnumerator(this);
+ public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ {
+ return new AsyncShaperEnumerator(this, cancellationToken);
+ }
private class AsyncShaperEnumerator : IAsyncEnumerator
{
private readonly IAsyncEnumerator _enumerator;
private readonly Func _shaper;
- public AsyncShaperEnumerator(AsyncShaperEnumerable enumerable)
+ public AsyncShaperEnumerator(AsyncShaperEnumerable enumerable, CancellationToken cancellationToken)
{
- _enumerator = enumerable._innerEnumerable.GetEnumerator();
+ _enumerator = enumerable._innerEnumerable.GetAsyncEnumerator(cancellationToken);
_shaper = enumerable._shaper;
}
+ public T Current { get; private set; }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public async Task MoveNext(CancellationToken cancellationToken)
+ public async ValueTask MoveNextAsync()
{
- if (!await _enumerator.MoveNext(cancellationToken))
+ if (!await _enumerator.MoveNextAsync())
{
Current = default;
return false;
@@ -108,9 +113,12 @@ public async Task MoveNext(CancellationToken cancellationToken)
return true;
}
- public T Current { get; private set; }
+ public ValueTask DisposeAsync()
+ {
+ _enumerator.DisposeAsync();
- public void Dispose() => _enumerator.Dispose();
+ return default;
+ }
}
}
diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs
index a473feb763b..db36cef614a 100644
--- a/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs
+++ b/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs
@@ -428,8 +428,8 @@ public DocumentAsyncEnumerable(
_cosmosSqlQuery = cosmosSqlQuery;
}
- public IAsyncEnumerator GetEnumerator() => new AsyncEnumerator(this);
-
+ public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ => new AsyncEnumerator(this, cancellationToken);
private class AsyncEnumerator : IAsyncEnumerator
{
private CosmosResultSetIterator _query;
@@ -439,20 +439,23 @@ private class AsyncEnumerator : IAsyncEnumerator
private readonly CosmosClientWrapper _cosmosClient;
private readonly string _containerId;
private readonly CosmosSqlQuery _cosmosSqlQuery;
+ private readonly CancellationToken _cancellationToken;
- public AsyncEnumerator(DocumentAsyncEnumerable documentEnumerable)
+ public AsyncEnumerator(DocumentAsyncEnumerable documentEnumerable, CancellationToken cancellationToken)
{
_cosmosClient = documentEnumerable._cosmosClient;
_containerId = documentEnumerable._containerId;
_cosmosSqlQuery = documentEnumerable._cosmosSqlQuery;
+ _cancellationToken = cancellationToken;
}
public JObject Current { get; private set; }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public async Task MoveNext(CancellationToken cancellationToken)
+ public async ValueTask MoveNextAsync()
{
- cancellationToken.ThrowIfCancellationRequested();
+ _cancellationToken.ThrowIfCancellationRequested();
if (_jsonReader == null)
{
@@ -467,7 +470,7 @@ public async Task MoveNext(CancellationToken cancellationToken)
return false;
}
- _responseStream = (await _query.FetchNextSetAsync(cancellationToken)).Content;
+ _responseStream = (await _query.FetchNextSetAsync(_cancellationToken)).Content;
_reader = new StreamReader(_responseStream);
_jsonReader = new JsonTextReader(_reader);
@@ -510,10 +513,10 @@ public async Task MoveNext(CancellationToken cancellationToken)
_reader = null;
_responseStream.Dispose();
_responseStream = null;
- return await MoveNext(cancellationToken);
+ return await MoveNextAsync();
}
- public void Dispose()
+ public ValueTask DisposeAsync()
{
_jsonReader?.Close();
_jsonReader = null;
@@ -521,9 +524,9 @@ public void Dispose()
_reader = null;
_responseStream?.Dispose();
_responseStream = null;
- }
- public void Reset() => throw new NotImplementedException();
+ return default;
+ }
}
}
diff --git a/src/EFCore.Design/EFCore.Design.csproj b/src/EFCore.Design/EFCore.Design.csproj
index 5c615c3bbf8..8b274c913d0 100644
--- a/src/EFCore.Design/EFCore.Design.csproj
+++ b/src/EFCore.Design/EFCore.Design.csproj
@@ -2,7 +2,7 @@
Shared design-time components for Entity Framework Core tools.
- netstandard2.0
+ netstandard2.1
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore
true
@@ -20,7 +20,7 @@
build
-
+
diff --git a/src/EFCore.InMemory/EFCore.InMemory.csproj b/src/EFCore.InMemory/EFCore.InMemory.csproj
index 23f40b2f7f1..d5fa1fe00df 100644
--- a/src/EFCore.InMemory/EFCore.InMemory.csproj
+++ b/src/EFCore.InMemory/EFCore.InMemory.csproj
@@ -2,7 +2,7 @@
In-memory database provider for Entity Framework Core (to be used for testing purposes).
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.InMemory
Microsoft.EntityFrameworkCore.InMemory
diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs
index d386fe407de..b1df74189f1 100644
--- a/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs
+++ b/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs
@@ -232,7 +232,8 @@ public AsyncQueryingEnumerable(
_logger = logger;
}
- public IAsyncEnumerator GetEnumerator() => new AsyncEnumerator(this);
+ public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ => new AsyncEnumerator(this, cancellationToken);
private sealed class AsyncEnumerator : IAsyncEnumerator
{
@@ -242,21 +243,23 @@ private sealed class AsyncEnumerator : IAsyncEnumerator
private readonly Func, Task> _shaper;
private readonly Type _contextType;
private readonly IDiagnosticsLogger _logger;
+ private readonly CancellationToken _cancellationToken;
- public AsyncEnumerator(AsyncQueryingEnumerable asyncQueryingEnumerable)
+ public AsyncEnumerator(
+ AsyncQueryingEnumerable asyncQueryingEnumerable,
+ CancellationToken cancellationToken)
{
_queryContext = asyncQueryingEnumerable._queryContext;
_innerEnumerable = asyncQueryingEnumerable._innerEnumerable;
_shaper = asyncQueryingEnumerable._shaper;
_contextType = asyncQueryingEnumerable._contextType;
_logger = asyncQueryingEnumerable._logger;
+ _cancellationToken = cancellationToken;
}
public T Current { get; private set; }
- public void Dispose() => _enumerator?.Dispose();
-
- public async Task MoveNext(CancellationToken cancellationToken)
+ public async ValueTask MoveNextAsync()
{
try
{
@@ -280,6 +283,13 @@ public async Task MoveNext(CancellationToken cancellationToken)
throw;
}
}
+
+ public ValueTask DisposeAsync()
+ {
+ _enumerator?.Dispose();
+
+ return default;
+ }
}
}
diff --git a/src/EFCore.Proxies/EFCore.Proxies.csproj b/src/EFCore.Proxies/EFCore.Proxies.csproj
index a2b35c3ee20..d7f9bd0f8bf 100644
--- a/src/EFCore.Proxies/EFCore.Proxies.csproj
+++ b/src/EFCore.Proxies/EFCore.Proxies.csproj
@@ -2,7 +2,7 @@
Lazy-loading proxies for EF Core.
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.Proxies
Microsoft.EntityFrameworkCore
diff --git a/src/EFCore.Relational/EFCore.Relational.csproj b/src/EFCore.Relational/EFCore.Relational.csproj
index e608c8c3804..b97ea3461b7 100644
--- a/src/EFCore.Relational/EFCore.Relational.csproj
+++ b/src/EFCore.Relational/EFCore.Relational.csproj
@@ -2,7 +2,7 @@
Shared Entity Framework Core components for relational database providers.
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.Relational
Microsoft.EntityFrameworkCore
diff --git a/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs b/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs
index c5d18b20d33..85f47fb6919 100644
--- a/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs
+++ b/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs
@@ -46,7 +46,8 @@ public AsyncQueryingEnumerable(
_logger = logger;
}
- public IAsyncEnumerator GetEnumerator() => new AsyncEnumerator(this);
+ public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ => new AsyncEnumerator(this, cancellationToken);
private sealed class AsyncEnumerator : IAsyncEnumerator
{
@@ -60,8 +61,11 @@ private sealed class AsyncEnumerator : IAsyncEnumerator
private readonly IDiagnosticsLogger _logger;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private readonly IParameterNameGeneratorFactory _parameterNameGeneratorFactory;
+ private readonly CancellationToken _cancellationToken;
- public AsyncEnumerator(AsyncQueryingEnumerable queryingEnumerable)
+ public AsyncEnumerator(
+ AsyncQueryingEnumerable queryingEnumerable,
+ CancellationToken cancellationToken)
{
_relationalQueryContext = queryingEnumerable._relationalQueryContext;
_shaper = queryingEnumerable._shaper;
@@ -71,24 +75,18 @@ public AsyncEnumerator(AsyncQueryingEnumerable queryingEnumerable)
_logger = queryingEnumerable._logger;
_sqlExpressionFactory = queryingEnumerable._sqlExpressionFactory;
_parameterNameGeneratorFactory = queryingEnumerable._parameterNameGeneratorFactory;
+ _cancellationToken = cancellationToken;
}
public T Current { get; private set; }
- public void Dispose()
- {
- _dataReader?.Dispose();
- _dataReader = null;
- _relationalQueryContext.Connection.Close();
- }
-
- public async Task MoveNext(CancellationToken cancellationToken)
+ public async ValueTask MoveNextAsync()
{
try
{
if (_dataReader == null)
{
- await _relationalQueryContext.Connection.OpenAsync(cancellationToken);
+ await _relationalQueryContext.Connection.OpenAsync(_cancellationToken);
try
{
@@ -104,7 +102,7 @@ public async Task MoveNext(CancellationToken cancellationToken)
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalQueryContext.CommandLogger,
- cancellationToken);
+ _cancellationToken);
_resultCoordinator = new ResultCoordinator();
}
@@ -118,7 +116,7 @@ public async Task MoveNext(CancellationToken cancellationToken)
}
}
- var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(cancellationToken);
+ var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(_cancellationToken);
_resultCoordinator.HasNext = null;
Current
@@ -135,6 +133,15 @@ public async Task MoveNext(CancellationToken cancellationToken)
throw;
}
}
+
+ public ValueTask DisposeAsync()
+ {
+ _dataReader?.Dispose();
+ _dataReader = null;
+ _relationalQueryContext.Connection.Close();
+
+ return default;
+ }
}
}
}
diff --git a/src/EFCore.Relational/Query/Pipeline/FromSqlNonComposedAsyncQueryingEnumerable.cs b/src/EFCore.Relational/Query/Pipeline/FromSqlNonComposedAsyncQueryingEnumerable.cs
index bf9bbfce221..ebfbc287d9c 100644
--- a/src/EFCore.Relational/Query/Pipeline/FromSqlNonComposedAsyncQueryingEnumerable.cs
+++ b/src/EFCore.Relational/Query/Pipeline/FromSqlNonComposedAsyncQueryingEnumerable.cs
@@ -47,7 +47,8 @@ public FromSqlNonComposedAsyncQueryingEnumerable(
_logger = logger;
}
- public IAsyncEnumerator GetEnumerator() => new AsyncEnumerator(this);
+ public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ => new AsyncEnumerator(this, cancellationToken);
private sealed class AsyncEnumerator : IAsyncEnumerator
{
@@ -61,8 +62,11 @@ private sealed class AsyncEnumerator : IAsyncEnumerator
private readonly IDiagnosticsLogger _logger;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private readonly IParameterNameGeneratorFactory _parameterNameGeneratorFactory;
+ private readonly CancellationToken _cancellationToken;
- public AsyncEnumerator(FromSqlNonComposedAsyncQueryingEnumerable queryingEnumerable)
+ public AsyncEnumerator(
+ FromSqlNonComposedAsyncQueryingEnumerable queryingEnumerable,
+ CancellationToken cancellationToken)
{
_relationalQueryContext = queryingEnumerable._relationalQueryContext;
_shaper = queryingEnumerable._shaper;
@@ -72,19 +76,12 @@ public AsyncEnumerator(FromSqlNonComposedAsyncQueryingEnumerable queryingEnum
_logger = queryingEnumerable._logger;
_sqlExpressionFactory = queryingEnumerable._sqlExpressionFactory;
_parameterNameGeneratorFactory = queryingEnumerable._parameterNameGeneratorFactory;
+ _cancellationToken = cancellationToken;
}
public T Current { get; private set; }
-
- public void Dispose()
- {
- _dataReader?.Dispose();
- _dataReader = null;
- _relationalQueryContext.Connection.Close();
- }
-
- public async Task MoveNext(CancellationToken cancellationToken)
+ public async ValueTask MoveNextAsync()
{
try
{
@@ -108,7 +105,7 @@ public async Task MoveNext(CancellationToken cancellationToken)
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalQueryContext.CommandLogger,
- cancellationToken);
+ _cancellationToken);
var readerColumns = Enumerable.Range(0, _dataReader.DbDataReader.FieldCount)
.Select(
@@ -153,7 +150,7 @@ var readerColumn
}
}
- var hasNext = await _dataReader.ReadAsync(cancellationToken);
+ var hasNext = await _dataReader.ReadAsync(_cancellationToken);
Current
= hasNext
@@ -170,7 +167,14 @@ var readerColumn
}
}
- public void Reset() => throw new NotImplementedException();
+ public ValueTask DisposeAsync()
+ {
+ _dataReader?.Dispose();
+ _dataReader = null;
+ _relationalQueryContext.Connection.Close();
+
+ return default;
+ }
}
}
}
diff --git a/src/EFCore.SqlServer.NTS/EFCore.SqlServer.NTS.csproj b/src/EFCore.SqlServer.NTS/EFCore.SqlServer.NTS.csproj
index b625680c3e2..5d9c9d58c0b 100644
--- a/src/EFCore.SqlServer.NTS/EFCore.SqlServer.NTS.csproj
+++ b/src/EFCore.SqlServer.NTS/EFCore.SqlServer.NTS.csproj
@@ -2,7 +2,7 @@
NetTopologySuite support for the Microsoft SQL Server database provider for Entity Framework Core.
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
Microsoft.EntityFrameworkCore.SqlServer
diff --git a/src/EFCore.SqlServer/EFCore.SqlServer.csproj b/src/EFCore.SqlServer/EFCore.SqlServer.csproj
index 35dfa22de64..73cf7177bb2 100644
--- a/src/EFCore.SqlServer/EFCore.SqlServer.csproj
+++ b/src/EFCore.SqlServer/EFCore.SqlServer.csproj
@@ -2,7 +2,7 @@
Microsoft SQL Server database provider for Entity Framework Core.
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer
diff --git a/src/EFCore.Sqlite.Core/EFCore.Sqlite.Core.csproj b/src/EFCore.Sqlite.Core/EFCore.Sqlite.Core.csproj
index ec3db282304..f8cec9a9c03 100644
--- a/src/EFCore.Sqlite.Core/EFCore.Sqlite.Core.csproj
+++ b/src/EFCore.Sqlite.Core/EFCore.Sqlite.Core.csproj
@@ -5,7 +5,7 @@
Microsoft.EntityFrameworkCore.Sqlite.Core
Microsoft.EntityFrameworkCore.Sqlite
SQLite database provider for Entity Framework Core.
- netstandard2.0
+ netstandard2.1
3.6
true
$(PackageTags);SQLite
diff --git a/src/EFCore.Sqlite.NTS/EFCore.Sqlite.NTS.csproj b/src/EFCore.Sqlite.NTS/EFCore.Sqlite.NTS.csproj
index 85d935382b8..215f5642b92 100644
--- a/src/EFCore.Sqlite.NTS/EFCore.Sqlite.NTS.csproj
+++ b/src/EFCore.Sqlite.NTS/EFCore.Sqlite.NTS.csproj
@@ -5,7 +5,7 @@
Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite
Microsoft.EntityFrameworkCore.Sqlite
NetTopologySuite support for the SQLite database provider for Entity Framework Core.
- netstandard2.0
+ netstandard2.1
3.6
true
$(PackageTags);SQLite;GIS;NTS;OGC;SpatiaLite
diff --git a/src/EFCore.Sqlite/EFCore.Sqlite.csproj b/src/EFCore.Sqlite/EFCore.Sqlite.csproj
index 3a5829057f8..0163f33a067 100644
--- a/src/EFCore.Sqlite/EFCore.Sqlite.csproj
+++ b/src/EFCore.Sqlite/EFCore.Sqlite.csproj
@@ -4,7 +4,7 @@
SQLite database provider for Entity Framework Core.
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore.Sqlite
$(PackageTags);SQLite
diff --git a/src/EFCore.Sqlite/lib/netstandard2.0/_._ b/src/EFCore.Sqlite/lib/netstandard2.1/_._
similarity index 100%
rename from src/EFCore.Sqlite/lib/netstandard2.0/_._
rename to src/EFCore.Sqlite/lib/netstandard2.1/_._
diff --git a/src/EFCore.Tools/lib/netstandard2.0/_._ b/src/EFCore.Tools/lib/netstandard2.1/_._
similarity index 100%
rename from src/EFCore.Tools/lib/netstandard2.0/_._
rename to src/EFCore.Tools/lib/netstandard2.1/_._
diff --git a/src/EFCore/EF.CompileAsyncQuery.cs b/src/EFCore/EF.CompileAsyncQuery.cs
index 4adc770ac5b..2af88eef194 100644
--- a/src/EFCore/EF.CompileAsyncQuery.cs
+++ b/src/EFCore/EF.CompileAsyncQuery.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
@@ -22,7 +23,7 @@ public static partial class EF
/// The query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery(
+ public static Func> CompileAsyncQuery(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
where TResult : class
@@ -36,7 +37,7 @@ public static Func> CompileAsyncQueryThe LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
[Obsolete("Use DbSet instead")]
- public static Func> CompileAsyncQuery(
+ public static Func> CompileAsyncQuery(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
where TResult : class
@@ -49,7 +50,7 @@ public static Func> CompileAsyncQueryThe query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery(
+ public static Func> CompileAsyncQuery(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
=> new CompiledAsyncEnumerableQuery(queryExpression).Execute;
@@ -62,7 +63,7 @@ public static Func> CompileAsyncQueryThe query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery(
+ public static Func> CompileAsyncQuery(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
=> new CompiledAsyncEnumerableQuery(queryExpression).Execute;
@@ -76,7 +77,7 @@ public static Func> CompileAsyncQuer
/// The query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery<
+ public static Func> CompileAsyncQuery<
TContext, TParam1, TParam2, TResult>(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
@@ -92,7 +93,7 @@ public static Func> Compile
/// The query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery<
+ public static Func> CompileAsyncQuery<
TContext, TParam1, TParam2, TParam3, TResult>(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
@@ -109,7 +110,7 @@ public static Func
/// The query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery<
+ public static Func> CompileAsyncQuery<
TContext, TParam1, TParam2, TParam3, TParam4, TResult>(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
@@ -127,7 +128,7 @@ public static FuncThe query result type.
/// The LINQ query expression.
/// A delegate that can be invoked to execute the compiled query.
- public static Func> CompileAsyncQuery<
+ public static Func> CompileAsyncQuery<
TContext, TParam1, TParam2, TParam3, TParam4, TParam5, TResult>(
[NotNull] Expression>> queryExpression)
where TContext : DbContext
diff --git a/src/EFCore/EFCore.csproj b/src/EFCore/EFCore.csproj
index 1216c467c02..da6e7fda382 100644
--- a/src/EFCore/EFCore.csproj
+++ b/src/EFCore/EFCore.csproj
@@ -7,7 +7,7 @@ Commonly Used Types:
Microsoft.EntityFrameworkCore.DbContext
Microsoft.EntityFrameworkCore.DbSet
- netstandard2.0
+ netstandard2.1
3.6
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore
diff --git a/src/EFCore/EntityFrameworkEnumerableExtensions.cs b/src/EFCore/EntityFrameworkEnumerableExtensions.cs
new file mode 100644
index 00000000000..574dcfee82c
--- /dev/null
+++ b/src/EFCore/EntityFrameworkEnumerableExtensions.cs
@@ -0,0 +1,440 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Extensions.Internal;
+using Microsoft.EntityFrameworkCore.Utilities;
+
+// ReSharper disable once CheckNamespace
+namespace Microsoft.EntityFrameworkCore
+{
+ public static class EntityFrameworkEnumerableExtensions
+ {
+ #region ToList/Array
+
+ ///
+ /// Asynchronously creates a from an by enumerating it
+ /// asynchronously.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// An to create a list from.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains elements from the input sequence.
+ ///
+ public static async Task> ToListAsync(
+ [NotNull] this IAsyncEnumerable source,
+ CancellationToken cancellationToken = default)
+ {
+ var list = new List();
+ await foreach (var element in source.WithCancellation(cancellationToken))
+ {
+ list.Add(element);
+ }
+
+ return list;
+ }
+
+ ///
+ /// Asynchronously creates an array from an by enumerating it asynchronously.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// An to create an array from.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains an array that contains elements from the input sequence.
+ ///
+ public static async Task ToArrayAsync(
+ [NotNull] this IAsyncEnumerable source,
+ CancellationToken cancellationToken = default)
+ => (await source.ToListAsync(cancellationToken)).ToArray();
+
+ #endregion
+
+ #region ToDictionary
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector function.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains selected keys and values.
+ ///
+ public static Task> ToDictionaryAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ CancellationToken cancellationToken = default)
+ => ToDictionaryAsync(source, keySelector, e => e, comparer: null, cancellationToken);
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector function and a comparer.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ ///
+ /// An to compare keys.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains selected keys and values.
+ ///
+ public static Task> ToDictionaryAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ [NotNull] IEqualityComparer comparer,
+ CancellationToken cancellationToken = default)
+ => ToDictionaryAsync(source, keySelector, e => e, comparer, cancellationToken);
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector and an element selector function.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// The type of the value returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains values of type
+ /// selected from the input sequence.
+ ///
+ public static Task> ToDictionaryAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ [NotNull] Func elementSelector,
+ CancellationToken cancellationToken = default)
+ => ToDictionaryAsync(source, keySelector, elementSelector, comparer: null, cancellationToken);
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector function, a comparer, and an element selector function.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// The type of the value returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ ///
+ /// An to compare keys.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains values of type
+ /// selected from the input sequence.
+ ///
+ public static async Task> ToDictionaryAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ [NotNull] Func elementSelector,
+ [NotNull] IEqualityComparer comparer,
+ CancellationToken cancellationToken = default)
+ {
+ Check.NotNull(source, nameof(source));
+ Check.NotNull(keySelector, nameof(keySelector));
+ Check.NotNull(elementSelector, nameof(elementSelector));
+ Check.NotNull(comparer, nameof(comparer));
+
+ var d = new Dictionary(comparer);
+ await foreach (var element in source.WithCancellation(cancellationToken))
+ {
+ d.Add(keySelector(element), elementSelector(element));
+ }
+
+ return d;
+ }
+
+ #endregion
+
+ #region ToLookup
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector function.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains selected keys and values.
+ ///
+ public static Task> ToLookupAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ CancellationToken cancellationToken = default)
+ => ToLookupAsync(source, keySelector, e => e, comparer: null, cancellationToken);
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector function and a comparer.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ ///
+ /// An to compare keys.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains selected keys and values.
+ ///
+ public static Task> ToLookupAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ [NotNull] IEqualityComparer comparer,
+ CancellationToken cancellationToken = default)
+ => ToLookupAsync(source, keySelector, e => e, comparer, cancellationToken);
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector and an element selector function.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// The type of the value returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains values of type
+ /// selected from the input sequence.
+ ///
+ public static Task> ToLookupAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ [NotNull] Func elementSelector,
+ CancellationToken cancellationToken = default)
+ => ToLookupAsync(source, keySelector, elementSelector, comparer: null, cancellationToken);
+
+ ///
+ /// Creates a from an by enumerating it
+ /// asynchronously
+ /// according to a specified key selector function, a comparer, and an element selector function.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// The type of the key returned by .
+ ///
+ ///
+ /// The type of the value returned by .
+ ///
+ ///
+ /// An to create a from.
+ ///
+ /// A function to extract a key from each element.
+ /// A transform function to produce a result element value from each element.
+ ///
+ /// An to compare keys.
+ ///
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// A task that represents the asynchronous operation.
+ /// The task result contains a that contains values of type
+ /// selected from the input sequence.
+ ///
+ public static Task> ToLookupAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Func keySelector,
+ [NotNull] Func elementSelector,
+ [NotNull] IEqualityComparer comparer,
+ CancellationToken cancellationToken = default)
+ {
+ Check.NotNull(source, nameof(source));
+ Check.NotNull(keySelector, nameof(keySelector));
+ Check.NotNull(elementSelector, nameof(elementSelector));
+ Check.NotNull(comparer, nameof(comparer));
+
+ throw new NotImplementedException("ToLookupAsync");
+ }
+
+ #endregion
+
+ #region ForEach
+
+ ///
+ /// Asynchronously enumerates the query results and performs the specified action on each element.
+ ///
+ ///
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
+ /// that any asynchronous operations have completed before calling another method on this context.
+ ///
+ ///
+ /// The type of the elements of .
+ ///
+ ///
+ /// An to enumerate.
+ ///
+ /// The action to perform on each element.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ /// A task that represents the asynchronous operation.
+ public static async Task ForEachAsync(
+ [NotNull] this IAsyncEnumerable source,
+ [NotNull] Action action,
+ CancellationToken cancellationToken = default)
+ {
+ Check.NotNull(action, nameof(action));
+
+ await foreach (var element in source.WithCancellation(cancellationToken))
+ {
+ action(element);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/EFCore/EntityFrameworkQueryableExtensions.cs b/src/EFCore/EntityFrameworkQueryableExtensions.cs
index c6bc3499a13..7aba45cc4bd 100644
--- a/src/EFCore/EntityFrameworkQueryableExtensions.cs
+++ b/src/EFCore/EntityFrameworkQueryableExtensions.cs
@@ -2128,7 +2128,7 @@ public static Task ContainsAsync(
public static Task> ToListAsync(
[NotNull] this IQueryable source,
CancellationToken cancellationToken = default)
- => source.AsAsyncEnumerable().ToList(cancellationToken);
+ => source.AsAsyncEnumerable().ToListAsync(cancellationToken);
///
/// Asynchronously creates an array from an by enumerating it asynchronously.
@@ -2153,7 +2153,7 @@ public static Task> ToListAsync(
public static Task ToArrayAsync(
[NotNull] this IQueryable source,
CancellationToken cancellationToken = default)
- => source.AsAsyncEnumerable().ToArray(cancellationToken);
+ => source.AsAsyncEnumerable().ToArrayAsync(cancellationToken);
#endregion
@@ -2401,12 +2401,12 @@ public IncludableQueryable(IQueryable queryable)
public Type ElementType => _queryable.ElementType;
public IQueryProvider Provider => _queryable.Provider;
+ public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ => ((IAsyncEnumerable)_queryable).GetAsyncEnumerator(cancellationToken);
+
public IEnumerator GetEnumerator() => _queryable.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- IAsyncEnumerator IAsyncEnumerable.GetEnumerator()
- => ((IAsyncEnumerable)_queryable).GetEnumerator();
}
internal static readonly MethodInfo StringIncludeMethodInfo
@@ -2686,11 +2686,9 @@ public static async Task LoadAsync(
{
Check.NotNull(source, nameof(source));
- var asyncEnumerable = source.AsAsyncEnumerable();
-
- using (var enumerator = asyncEnumerable.GetEnumerator())
+ await using (var enumerator = source.AsAsyncEnumerable().GetAsyncEnumerator(cancellationToken))
{
- while (await enumerator.MoveNext(cancellationToken))
+ while (await enumerator.MoveNextAsync())
{
}
}
@@ -2734,7 +2732,7 @@ public static Task> ToDictionaryAsync(
Check.NotNull(source, nameof(source));
Check.NotNull(keySelector, nameof(keySelector));
- return source.AsAsyncEnumerable().ToDictionary(keySelector, cancellationToken);
+ return source.AsAsyncEnumerable().ToDictionaryAsync(keySelector, cancellationToken);
}
///
@@ -2776,7 +2774,7 @@ public static Task> ToDictionaryAsync(
Check.NotNull(keySelector, nameof(keySelector));
Check.NotNull(comparer, nameof(comparer));
- return source.AsAsyncEnumerable().ToDictionary(keySelector, comparer, cancellationToken);
+ return source.AsAsyncEnumerable().ToDictionaryAsync(keySelector, comparer, cancellationToken);
}
///
@@ -2820,7 +2818,7 @@ public static Task> ToDictionaryAsync
@@ -2869,7 +2867,7 @@ public static Task> ToDictionaryAsync> ToLookupAsync(
Check.NotNull(source, nameof(source));
Check.NotNull(keySelector, nameof(keySelector));
- return source.AsAsyncEnumerable().ToLookup(keySelector, cancellationToken);
+ return source.AsAsyncEnumerable().ToLookupAsync(keySelector, cancellationToken);
}
///
@@ -2952,7 +2950,7 @@ public static Task> ToLookupAsync(
Check.NotNull(keySelector, nameof(keySelector));
Check.NotNull(comparer, nameof(comparer));
- return source.AsAsyncEnumerable().ToLookup(keySelector, comparer, cancellationToken);
+ return source.AsAsyncEnumerable().ToLookupAsync(keySelector, comparer, cancellationToken);
}
///
@@ -2996,7 +2994,7 @@ public static Task> ToLookupAsync
@@ -3045,7 +3043,7 @@ public static Task> ToLookupAsync
- public virtual void OnIndexRemoved([NotNull] InternalEntityTypeBuilder entityTypeBuilder, [NotNull] Index index)
+ public virtual void OnIndexRemoved([NotNull] InternalEntityTypeBuilder entityTypeBuilder, [NotNull] Metadata.Internal.Index index)
=> _scope.OnIndexRemoved(entityTypeBuilder, index);
///
diff --git a/src/EFCore/Query/AsyncEnumerable.cs b/src/EFCore/Query/AsyncEnumerable.cs
deleted file mode 100644
index 1427464ee48..00000000000
--- a/src/EFCore/Query/AsyncEnumerable.cs
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using JetBrains.Annotations;
-using Microsoft.EntityFrameworkCore.Query.Internal;
-using Microsoft.EntityFrameworkCore.Utilities;
-
-namespace Microsoft.EntityFrameworkCore.Query
-{
- ///
- /// Represents an asynchronous sequence produced by executing a compiled query.
- ///
- /// The result type.
- public readonly struct AsyncEnumerable : IAsyncEnumerableAccessor
- {
- private readonly IAsyncEnumerable _asyncEnumerable;
-
- ///
- /// Creates a new instance of
- ///
- /// The underlying instance.
- public AsyncEnumerable([NotNull] IAsyncEnumerable asyncEnumerable)
- {
- Check.NotNull(asyncEnumerable, nameof(asyncEnumerable));
-
- _asyncEnumerable = asyncEnumerable;
- }
-
- IAsyncEnumerable IAsyncEnumerableAccessor.AsyncEnumerable => _asyncEnumerable;
-
- ///
- /// Asynchronously creates a from this
- /// by enumerating it asynchronously.
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- ///
- /// A to observe while waiting for the task to complete.
- ///
- ///
- /// A task that represents the asynchronous operation.
- /// The task result contains a that contains elements from the input sequence.
- ///
- public async Task> ToListAsync(
- CancellationToken cancellationToken = default)
- {
- var list = new List();
-
- using (var asyncEnumerator = _asyncEnumerable.GetEnumerator())
- {
- while (await asyncEnumerator.MoveNext(cancellationToken))
- {
- list.Add(asyncEnumerator.Current);
- }
- }
-
- return list;
- }
-
- ///
- /// Asynchronously creates an array from this .
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- ///
- /// A to observe while waiting for the task to complete.
- ///
- ///
- /// A task that represents the asynchronous operation.
- /// The task result contains an array that contains elements from the input sequence.
- ///
- public async Task ToArrayAsync(
- CancellationToken cancellationToken = default)
- => (await ToListAsync(cancellationToken)).ToArray();
-
- ///
- /// Asynchronously enumerates the query. When using Entity Framework, this causes the results of the query to
- /// be loaded into the associated context. This is equivalent to calling ToList
- /// and then throwing away the list (without the overhead of actually creating the list).
- ///
- ///
- /// A to observe while waiting for the task to complete.
- ///
- /// A task that represents the asynchronous operation.
- public async Task LoadAsync(
- CancellationToken cancellationToken = default)
- {
- using (var enumerator = _asyncEnumerable.GetEnumerator())
- {
- while (await enumerator.MoveNext(cancellationToken))
- {
- }
- }
- }
-
- ///
- /// Creates a from this
- /// by enumerating it asynchronously according to a specified key selector function.
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- ///
- /// The type of the key returned by .
- ///
- /// A function to extract a key from each element.
- ///
- /// A to observe while waiting for the task to complete.
- ///
- ///
- /// A task that represents the asynchronous operation.
- /// The task result contains a that contains selected keys and values.
- ///
- public Task> ToDictionaryAsync(
- [NotNull] Func keySelector,
- CancellationToken cancellationToken = default)
- {
- Check.NotNull(keySelector, nameof(keySelector));
-
- return _asyncEnumerable.ToDictionary(keySelector, cancellationToken);
- }
-
- ///
- /// Creates a from this
- /// by enumerating it
- /// asynchronously
- /// according to a specified key selector function and a comparer.
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- ///
- /// The type of the key returned by .
- ///
- /// A function to extract a key from each element.
- ///
- /// An to compare keys.
- ///
- ///
- /// A to observe while waiting for the task to complete.
- ///
- ///
- /// A task that represents the asynchronous operation.
- /// The task result contains a that contains selected keys and values.
- ///
- public Task> ToDictionaryAsync(
- [NotNull] Func keySelector,
- [NotNull] IEqualityComparer comparer,
- CancellationToken cancellationToken = default)
- {
- Check.NotNull(keySelector, nameof(keySelector));
- Check.NotNull(comparer, nameof(comparer));
-
- return _asyncEnumerable.ToDictionary(keySelector, comparer, cancellationToken);
- }
-
- ///
- /// Creates a from this
- /// by enumerating it asynchronously according to a specified key selector and an element selector function.
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- ///
- /// The type of the key returned by .
- ///
- ///
- /// The type of the value returned by .
- ///
- /// A function to extract a key from each element.
- /// A transform function to produce a result element value from each element.
- ///
- /// A to observe while waiting for the task to complete.
- ///
- ///
- /// A task that represents the asynchronous operation.
- /// The task result contains a that contains values of type
- /// selected from the input sequence.
- ///
- public Task> ToDictionaryAsync(
- [NotNull] Func keySelector,
- [NotNull] Func elementSelector,
- CancellationToken cancellationToken = default)
- {
- Check.NotNull(keySelector, nameof(keySelector));
- Check.NotNull(elementSelector, nameof(elementSelector));
-
- return _asyncEnumerable.ToDictionary(keySelector, elementSelector, cancellationToken);
- }
-
- ///
- /// Creates a from this
- /// by enumerating it asynchronously according to a specified key selector function, a comparer, and an element selector function.
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- ///
- /// The type of the key returned by .
- ///
- ///
- /// The type of the value returned by .
- ///
- /// A function to extract a key from each element.
- /// A transform function to produce a result element value from each element.
- ///
- /// An to compare keys.
- ///
- ///
- /// A to observe while waiting for the task to complete.
- ///
- ///
- /// A task that represents the asynchronous operation.
- /// The task result contains a that contains values of type
- /// selected from the input sequence.
- ///
- public Task> ToDictionaryAsync(
- [NotNull] Func keySelector,
- [NotNull] Func elementSelector,
- [NotNull] IEqualityComparer comparer,
- CancellationToken cancellationToken = default)
- {
- Check.NotNull(keySelector, nameof(keySelector));
- Check.NotNull(elementSelector, nameof(elementSelector));
- Check.NotNull(comparer, nameof(comparer));
-
- return _asyncEnumerable.ToDictionary(keySelector, elementSelector, comparer, cancellationToken);
- }
-
- ///
- /// Asynchronously enumerates the query results and performs the specified action on each element.
- ///
- ///
- /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
- /// that any asynchronous operations have completed before calling another method on this context.
- ///
- /// The action to perform on each element.
- ///
- /// A to observe while waiting for the task to complete.
- ///
- /// A task that represents the asynchronous operation.
- public async Task ForEachAsync(
- [NotNull] Action action,
- CancellationToken cancellationToken = default)
- {
- Check.NotNull(action, nameof(action));
-
- using (var asyncEnumerator = _asyncEnumerable.GetEnumerator())
- {
- while (await asyncEnumerator.MoveNext(cancellationToken))
- {
- action(asyncEnumerator.Current);
- }
- }
- }
- }
-}
diff --git a/src/EFCore/Query/Internal/CompiledAsyncEnumerableQuery.cs b/src/EFCore/Query/Internal/CompiledAsyncEnumerableQuery.cs
index 755c4a6a603..1e4b95c7e19 100644
--- a/src/EFCore/Query/Internal/CompiledAsyncEnumerableQuery.cs
+++ b/src/EFCore/Query/Internal/CompiledAsyncEnumerableQuery.cs
@@ -14,7 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public class CompiledAsyncEnumerableQuery : CompiledQueryBase>
+ public class CompiledAsyncEnumerableQuery : CompiledQueryBase>
where TContext : DbContext
{
///
@@ -34,7 +34,7 @@ public CompiledAsyncEnumerableQuery([NotNull] LambdaExpression queryExpression)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual AsyncEnumerable Execute(
+ public virtual IAsyncEnumerable Execute(
[NotNull] TContext context)
=> ExecuteCore(context);
@@ -44,7 +44,7 @@ public virtual AsyncEnumerable Execute(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual AsyncEnumerable Execute(
+ public virtual IAsyncEnumerable Execute(
[NotNull] TContext context,
[CanBeNull] TParam1 param1)
=> ExecuteCore(context, param1);
@@ -55,7 +55,7 @@ public virtual AsyncEnumerable Execute(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual AsyncEnumerable Execute(
+ public virtual IAsyncEnumerable Execute(
[NotNull] TContext context,
[CanBeNull] TParam1 param1,
[CanBeNull] TParam2 param2)
@@ -67,7 +67,7 @@ public virtual AsyncEnumerable Execute(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual AsyncEnumerable Execute(
+ public virtual IAsyncEnumerable Execute(
[NotNull] TContext context,
[CanBeNull] TParam1 param1,
[CanBeNull] TParam2 param2,
@@ -80,7 +80,7 @@ public virtual AsyncEnumerable Execute(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual AsyncEnumerable Execute(
+ public virtual IAsyncEnumerable Execute(
[NotNull] TContext context,
[CanBeNull] TParam1 param1,
[CanBeNull] TParam2 param2,
@@ -94,7 +94,7 @@ public virtual AsyncEnumerable Execute
- public virtual AsyncEnumerable Execute(
+ public virtual IAsyncEnumerable Execute(
[NotNull] TContext context,
[CanBeNull] TParam1 param1,
[CanBeNull] TParam2 param2,
@@ -109,12 +109,10 @@ public virtual AsyncEnumerable Execute
- protected override Func> CreateCompiledQuery(
+ protected override Func> CreateCompiledQuery(
IQueryCompiler queryCompiler, Expression expression)
{
- var compiledQuery = queryCompiler.CreateCompiledAsyncQuery>(expression);
-
- return qc => new AsyncEnumerable(compiledQuery(qc));
+ return queryCompiler.CreateCompiledAsyncQuery>(expression);
}
}
}
diff --git a/src/EFCore/Query/Internal/EntityQueryable`.cs b/src/EFCore/Query/Internal/EntityQueryable`.cs
index 33fba531782..5bac44da27a 100644
--- a/src/EFCore/Query/Internal/EntityQueryable`.cs
+++ b/src/EFCore/Query/Internal/EntityQueryable`.cs
@@ -7,6 +7,7 @@
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
+using System.Threading;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -107,8 +108,8 @@ IEnumerator IEnumerable.GetEnumerator()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- IAsyncEnumerator IAsyncEnumerable.GetEnumerator()
- => _queryProvider.ExecuteAsync>(Expression).GetEnumerator();
+ public virtual IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
+ => _queryProvider.ExecuteAsync>(Expression).GetAsyncEnumerator(cancellationToken);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
diff --git a/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs b/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs
index b2598c60d17..9ebf557697f 100644
--- a/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs
+++ b/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs
@@ -98,16 +98,16 @@ private async static Task SingleAsync(
IAsyncEnumerable asyncEnumerable,
CancellationToken cancellationToken = default)
{
- using (var enumerator = asyncEnumerable.GetEnumerator())
+ await using (var enumerator = asyncEnumerable.GetAsyncEnumerator(cancellationToken))
{
- if (!(await enumerator.MoveNext(cancellationToken)))
+ if (!(await enumerator.MoveNextAsync()))
{
throw new InvalidOperationException();
}
var result = enumerator.Current;
- if (await enumerator.MoveNext(cancellationToken))
+ if (await enumerator.MoveNextAsync())
{
throw new InvalidOperationException();
}
@@ -119,16 +119,16 @@ private async static Task SingleOrDefaultAsync(
IAsyncEnumerable asyncEnumerable,
CancellationToken cancellationToken = default)
{
- using (var enumerator = asyncEnumerable.GetEnumerator())
+ await using (var enumerator = asyncEnumerable.GetAsyncEnumerator(cancellationToken))
{
- if (!(await enumerator.MoveNext()))
+ if (!(await enumerator.MoveNextAsync()))
{
return default;
}
var result = enumerator.Current;
- if (await enumerator.MoveNext())
+ if (await enumerator.MoveNextAsync())
{
throw new InvalidOperationException();
}
diff --git a/src/Shared/SharedTypeExtensions.cs b/src/Shared/SharedTypeExtensions.cs
index de1e78aadf5..ab839a42dd1 100644
--- a/src/Shared/SharedTypeExtensions.cs
+++ b/src/Shared/SharedTypeExtensions.cs
@@ -115,13 +115,6 @@ private static bool IsInstantiable(TypeInfo type)
&& !type.IsInterface
&& (!type.IsGenericType || !type.IsGenericTypeDefinition);
- public static bool IsGrouping(this Type type) => IsGrouping(type.GetTypeInfo());
-
- private static bool IsGrouping(TypeInfo type)
- => type.IsGenericType
- && (type.GetGenericTypeDefinition() == typeof(IGrouping<,>)
- || type.GetGenericTypeDefinition() == typeof(IAsyncGrouping<,>));
-
public static Type UnwrapEnumType(this Type type)
{
var isNullable = type.IsNullableType();
diff --git a/test/EFCore.Specification.Tests/TestUtilities/QueryableExtensions.cs b/test/EFCore.Specification.Tests/TestUtilities/QueryableExtensions.cs
index 8213532f07e..dd5446f7348 100644
--- a/test/EFCore.Specification.Tests/TestUtilities/QueryableExtensions.cs
+++ b/test/EFCore.Specification.Tests/TestUtilities/QueryableExtensions.cs
@@ -14,19 +14,9 @@ public static class QueryableExtensions
public static List ToList(this System.Collections.IEnumerable source)
=> source.OfType().ToList();
- public static async Task> ToListAsync(this IQueryable source, CancellationToken cancellationToken = default)
+ public static Task> ToListAsync(this IQueryable source, CancellationToken cancellationToken = default)
{
- var list = new List();
-
- using (var e = ((IQueryable)source).AsAsyncEnumerable().GetEnumerator())
- {
- while (await e.MoveNext(cancellationToken).ConfigureAwait(false))
- {
- list.Add(e.Current);
- }
- }
-
- return list;
+ return ((IQueryable)source).ToListAsync(cancellationToken);
}
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs
index a1bbac1890f..62a36fc0dfa 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs
@@ -161,9 +161,9 @@ public async Task Concurrent_async_queries_when_raw_query()
{
using (var context = CreateContext())
{
- using (var asyncEnumerator = context.Customers.AsAsyncEnumerable().GetEnumerator())
+ await using (var asyncEnumerator = context.Customers.AsAsyncEnumerable().GetAsyncEnumerator())
{
- while (await asyncEnumerator.MoveNext(default))
+ while (await asyncEnumerator.MoveNextAsync())
{
if (!context.GetService().IsMultipleActiveResultSetsEnabled)
{
diff --git a/test/EFCore.Tests/Utilities/TypeExtensionsTest.cs b/test/EFCore.Tests/Utilities/TypeExtensionsTest.cs
index 50926c5968f..e5f03e219c2 100644
--- a/test/EFCore.Tests/Utilities/TypeExtensionsTest.cs
+++ b/test/EFCore.Tests/Utilities/TypeExtensionsTest.cs
@@ -1,10 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-#if NETCOREAPP3_0
-// workaround the overlap between System.Interactive.Async and System.Runtime
-extern alias reactive;
-#endif
using System;
using System.Collections;
using System.Collections.Generic;
@@ -25,11 +21,7 @@ public void GetSequenceType_finds_element_type()
{
Assert.Equal(typeof(int), typeof(IEnumerable).GetSequenceType());
Assert.Equal(typeof(int), typeof(IQueryable).GetSequenceType());
-#if NETCOREAPP3_0
- Assert.Equal(typeof(int), typeof(reactive::System.Collections.Generic.IAsyncEnumerable).GetSequenceType());
-#else
Assert.Equal(typeof(int), typeof(IAsyncEnumerable).GetSequenceType());
-#endif
Assert.Equal(typeof(int), typeof(List).GetSequenceType());
}