diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ba386a5b646..42204758929 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,6 +1,14 @@ + + https://github.com/dotnet/corefx + 6a4153689e79a8e58ee3ed77e04d04a0d9dc2ea6 + + + https://github.com/dotnet/corefx + 6a4153689e79a8e58ee3ed77e04d04a0d9dc2ea6 + https://github.com/dotnet/corefx 6a4153689e79a8e58ee3ed77e04d04a0d9dc2ea6 diff --git a/eng/Versions.props b/eng/Versions.props index 4e956bd46e0..35c50730496 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -40,6 +40,8 @@ 3.1.0-preview2.19501.2 + 1.1.0-preview1.19470.8 + 1.1.0-preview1.19470.8 4.7.0-preview1.19470.8 1.7.0-preview1.19470.8 4.7.0-preview1.19470.8 diff --git a/src/EFCore.Abstractions/EFCore.Abstractions.csproj b/src/EFCore.Abstractions/EFCore.Abstractions.csproj index eac661300e4..9eaa6bdf25b 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.Abstractions Microsoft.EntityFrameworkCore diff --git a/src/EFCore.Cosmos/EFCore.Cosmos.csproj b/src/EFCore.Cosmos/EFCore.Cosmos.csproj index 44922d8609e..b0a0ad17f0d 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.Cosmos Microsoft.EntityFrameworkCore.Cosmos diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs index b3dc032d485..a8f4d7f4a69 100644 --- a/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs +++ b/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs @@ -14,7 +14,6 @@ using Microsoft.Azure.Cosmos; using Microsoft.EntityFrameworkCore.Cosmos.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Cosmos.Infrastructure.Internal; -using Microsoft.EntityFrameworkCore.Cosmos.Internal; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; @@ -288,21 +287,35 @@ private async Task CreateItemOnceAsync( (string ContainerId, JToken Document, string PartitionKey) parameters, CancellationToken cancellationToken = default) { - await using (var stream = new MemoryStream()) - await using (var writer = new StreamWriter(stream, new UTF8Encoding(), bufferSize: 1024, leaveOpen: false)) - using (var jsonWriter = new JsonTextWriter(writer)) + var stream = new MemoryStream(); + try { - JsonSerializer.Create().Serialize(jsonWriter, parameters.Document); - await jsonWriter.FlushAsync(cancellationToken); + var writer = new StreamWriter(stream, new UTF8Encoding(), bufferSize: 1024, leaveOpen: false); + try + { + using (var jsonWriter = new JsonTextWriter(writer)) + { + JsonSerializer.Create().Serialize(jsonWriter, parameters.Document); + await jsonWriter.FlushAsync(cancellationToken); - var container = Client.GetDatabase(_databaseId).GetContainer(parameters.ContainerId); - var partitionKey = CreatePartitionKey(parameters.PartitionKey); - using (var response = await container.CreateItemStreamAsync(stream, partitionKey, null, cancellationToken)) + var container = Client.GetDatabase(_databaseId).GetContainer(parameters.ContainerId); + var partitionKey = CreatePartitionKey(parameters.PartitionKey); + using (var response = await container.CreateItemStreamAsync(stream, partitionKey, null, cancellationToken)) + { + response.EnsureSuccessStatusCode(); + return response.StatusCode == HttpStatusCode.Created; + } + } + } + finally { - response.EnsureSuccessStatusCode(); - return response.StatusCode == HttpStatusCode.Created; + await writer.DisposeAsyncIfAvailable(); } } + finally + { + await stream.DisposeAsyncIfAvailable(); + } } /// @@ -691,7 +704,7 @@ public async ValueTask DisposeAsync() _jsonReader = null; await _reader.DisposeAsyncIfAvailable(); _reader = null; - await _responseStream.DisposeAsync(); + await _responseStream.DisposeAsyncIfAvailable(); _responseStream = null; await _responseMessage.DisposeAsyncIfAvailable(); _responseMessage = null; diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosExecutionStrategy.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosExecutionStrategy.cs index 325d7ec9903..f7551495ebd 100644 --- a/src/EFCore.Cosmos/Storage/Internal/CosmosExecutionStrategy.cs +++ b/src/EFCore.Cosmos/Storage/Internal/CosmosExecutionStrategy.cs @@ -118,7 +118,7 @@ protected override bool ShouldRetryOn(Exception exception) static bool IsTransient(HttpStatusCode statusCode) => statusCode == HttpStatusCode.ServiceUnavailable - || statusCode == HttpStatusCode.TooManyRequests; + || statusCode == (HttpStatusCode)429; // TooManyRequests } /// diff --git a/src/EFCore.Design/Design/Internal/CSharpHelper.cs b/src/EFCore.Design/Design/Internal/CSharpHelper.cs index 15d7d23566d..793e4643388 100644 --- a/src/EFCore.Design/Design/Internal/CSharpHelper.cs +++ b/src/EFCore.Design/Design/Internal/CSharpHelper.cs @@ -193,7 +193,7 @@ public virtual string Lambda(IReadOnlyList properties) else { builder.Append("new { "); - builder.AppendJoin(", ", properties.Select(p => "x." + p)); + builder.Append(string.Join(", ", properties.Select(p => "x." + p))); builder.Append(" }"); } diff --git a/src/EFCore.Design/EFCore.Design.csproj b/src/EFCore.Design/EFCore.Design.csproj index 8b274c913d0..010cc9cddf6 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.1 + netstandard2.0 Microsoft.EntityFrameworkCore.Design Microsoft.EntityFrameworkCore true diff --git a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs index 18b802d7f37..13df459de43 100644 --- a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs +++ b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs @@ -168,7 +168,7 @@ protected virtual void GenerateEntityType( // ReSharper disable once InlineOutVariableDeclaration var counter = 1; if (builderName.Length > 1 - && int.TryParse(builderName[1..], out counter)) + && int.TryParse(builderName.Substring(1), out counter)) { counter++; } diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs index 6f3d5b567c8..ea981ad0c94 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs +++ b/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs @@ -401,7 +401,7 @@ public override string ToString() private static string StripAttribute([NotNull] string attributeName) => attributeName.EndsWith("Attribute", StringComparison.Ordinal) - ? attributeName[..^9] + ? attributeName.Substring(0, attributeName.Length - 9) : attributeName; } } diff --git a/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs b/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs index e8f50874bee..95c31686014 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs +++ b/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs @@ -158,7 +158,7 @@ private static string StripId(string commonPrefix) { return commonPrefix.Length > 2 && commonPrefix.EndsWith("id", StringComparison.OrdinalIgnoreCase) - ? commonPrefix[..^2] + ? commonPrefix.Substring(0, commonPrefix.Length - 2) : commonPrefix; } } diff --git a/src/EFCore.InMemory/EFCore.InMemory.csproj b/src/EFCore.InMemory/EFCore.InMemory.csproj index d5fa1fe00df..23f40b2f7f1 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.InMemory Microsoft.EntityFrameworkCore.InMemory diff --git a/src/EFCore.Proxies/EFCore.Proxies.csproj b/src/EFCore.Proxies/EFCore.Proxies.csproj index d7f9bd0f8bf..a2b35c3ee20 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.Proxies Microsoft.EntityFrameworkCore diff --git a/src/EFCore.Relational/Diagnostics/DbConnectionInterceptor.cs b/src/EFCore.Relational/Diagnostics/DbConnectionInterceptor.cs index 22328842d6c..a24cfe84366 100644 --- a/src/EFCore.Relational/Diagnostics/DbConnectionInterceptor.cs +++ b/src/EFCore.Relational/Diagnostics/DbConnectionInterceptor.cs @@ -112,7 +112,7 @@ public virtual InterceptionResult ConnectionClosing( => result; /// - /// Called just before EF intends to call in an async context. + /// Called just before EF intends to call in an async context. /// /// The connection. /// Contextual information about the connection. @@ -147,7 +147,7 @@ public virtual void ConnectionClosed( } /// - /// Called just after EF has called . + /// Called just after EF has called . /// /// The connection. /// Contextual information about the connection. diff --git a/src/EFCore.Relational/Diagnostics/DbTransactionInterceptor.cs b/src/EFCore.Relational/Diagnostics/DbTransactionInterceptor.cs index 02a815a1157..f54fb0118fa 100644 --- a/src/EFCore.Relational/Diagnostics/DbTransactionInterceptor.cs +++ b/src/EFCore.Relational/Diagnostics/DbTransactionInterceptor.cs @@ -67,7 +67,7 @@ public virtual DbTransaction TransactionStarted( => result; /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The connection. /// Contextual information about connection and transaction. @@ -92,7 +92,7 @@ public virtual Task> TransactionStartingAsync( /// /// - /// Called immediately after EF calls . + /// Called immediately after EF calls . /// /// /// This method is still called if an interceptor suppressed creation in . @@ -102,7 +102,7 @@ public virtual Task> TransactionStartingAsync( /// The connection. /// Contextual information about connection and transaction. /// - /// The result of the call to . + /// The result of the call to . /// This value is typically used as the return value for the implementation of this method. /// /// The cancellation token. @@ -198,7 +198,7 @@ public virtual void TransactionCommitted( } /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The transaction. /// Contextual information about connection and transaction. @@ -224,7 +224,7 @@ public virtual Task TransactionCommittingAsync( => Task.FromResult(result); /// - /// Called immediately after EF calls . + /// Called immediately after EF calls . /// /// The transaction. /// Contextual information about connection and transaction. @@ -272,7 +272,7 @@ public virtual void TransactionRolledBack( } /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The transaction. /// Contextual information about connection and transaction. @@ -298,7 +298,7 @@ public virtual Task TransactionRollingBackAsync( => Task.FromResult(result); /// - /// Called immediately after EF calls . + /// Called immediately after EF calls . /// /// The transaction. /// Contextual information about connection and transaction. diff --git a/src/EFCore.Relational/Diagnostics/IDbConnectionInterceptor.cs b/src/EFCore.Relational/Diagnostics/IDbConnectionInterceptor.cs index 2096bf14925..ef456f5c94b 100644 --- a/src/EFCore.Relational/Diagnostics/IDbConnectionInterceptor.cs +++ b/src/EFCore.Relational/Diagnostics/IDbConnectionInterceptor.cs @@ -101,7 +101,7 @@ Task ConnectionOpenedAsync( CancellationToken cancellationToken = default); /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The connection. /// Contextual information about the connection. @@ -156,7 +156,7 @@ void ConnectionClosed( [NotNull] ConnectionEndEventData eventData); /// - /// Called just after EF has called . + /// Called just after EF has called . /// /// The connection. /// Contextual information about the connection. diff --git a/src/EFCore.Relational/Diagnostics/IDbTransactionInterceptor.cs b/src/EFCore.Relational/Diagnostics/IDbTransactionInterceptor.cs index cde0de7552f..8092a7e437f 100644 --- a/src/EFCore.Relational/Diagnostics/IDbTransactionInterceptor.cs +++ b/src/EFCore.Relational/Diagnostics/IDbTransactionInterceptor.cs @@ -81,7 +81,7 @@ DbTransaction TransactionStarted( [CanBeNull] DbTransaction result); /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The connection. /// Contextual information about connection and transaction. @@ -107,7 +107,7 @@ Task> TransactionStartingAsync( /// /// - /// Called immediately after EF calls . + /// Called immediately after EF calls . /// /// /// This method is still called if an interceptor suppressed creation in . @@ -117,7 +117,7 @@ Task> TransactionStartingAsync( /// The connection. /// Contextual information about connection and transaction. /// - /// The result of the call to . + /// The result of the call to . /// This value is typically used as the return value for the implementation of this method. /// /// The cancellation token. @@ -210,7 +210,7 @@ void TransactionCommitted( [NotNull] TransactionEndEventData eventData); /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The transaction. /// Contextual information about connection and transaction. @@ -235,7 +235,7 @@ Task TransactionCommittingAsync( CancellationToken cancellationToken = default); /// - /// Called immediately after EF calls . + /// Called immediately after EF calls . /// /// The transaction. /// Contextual information about connection and transaction. @@ -279,7 +279,7 @@ void TransactionRolledBack( [NotNull] TransactionEndEventData eventData); /// - /// Called just before EF intends to call . + /// Called just before EF intends to call . /// /// The transaction. /// Contextual information about connection and transaction. @@ -304,7 +304,7 @@ Task TransactionRollingBackAsync( CancellationToken cancellationToken = default); /// - /// Called immediately after EF calls . + /// Called immediately after EF calls . /// /// The transaction. /// Contextual information about connection and transaction. diff --git a/src/EFCore.Relational/EFCore.Relational.csproj b/src/EFCore.Relational/EFCore.Relational.csproj index b97ea3461b7..e608c8c3804 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.Relational Microsoft.EntityFrameworkCore diff --git a/src/EFCore.Relational/Extensions/Internal/DbConnectionExtensions.cs b/src/EFCore.Relational/Extensions/Internal/DbConnectionExtensions.cs new file mode 100644 index 00000000000..d93eb8d6ff6 --- /dev/null +++ b/src/EFCore.Relational/Extensions/Internal/DbConnectionExtensions.cs @@ -0,0 +1,96 @@ +// 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.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Data.Common +{ + internal static class DbConnectionExtensions + { + private static readonly Func> _beginTransactionAsync; + private static readonly Func _closeAsync; + + static DbConnectionExtensions() + { + var beginTransactionAsync = typeof(DbConnection) + .GetMethod("BeginTransactionAsync", new[] { typeof(IsolationLevel), typeof(CancellationToken) }); + if (beginTransactionAsync != null) + { + var connection = Expression.Parameter(typeof(DbConnection), "connection"); + var isolationLevel = Expression.Parameter(typeof(IsolationLevel), "isolationLevel"); + var cancellationToken = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); + + _beginTransactionAsync = Expression + .Lambda>>( + Expression.Call(connection, beginTransactionAsync, isolationLevel, cancellationToken), + connection, + isolationLevel, + cancellationToken) + .Compile(); + } + else + { + _beginTransactionAsync = BeginTransactionSync; + } + + var closeAsync = typeof(DbConnection).GetMethod("CloseAsync", Type.EmptyTypes); + if (closeAsync != null) + { + var connection = Expression.Parameter(typeof(DbConnection), "connection"); + + _closeAsync = Expression + .Lambda>(Expression.Call(connection, closeAsync), connection) + .Compile(); + } + else + { + _closeAsync = CloseSync; + } + } + + public static ValueTask BeginTransactionAsync( + this DbConnection connection, + IsolationLevel isolationLevel, + CancellationToken cancellationToken) + => _beginTransactionAsync(connection, isolationLevel, cancellationToken); + + private static ValueTask BeginTransactionSync( + DbConnection connection, + IsolationLevel isolationLevel, + CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return new ValueTask(Task.FromCanceled(cancellationToken)); + } + + try + { + return new ValueTask(connection.BeginTransaction(isolationLevel)); + } + catch (Exception ex) + { + return new ValueTask(Task.FromException(ex)); + } + } + + public static Task CloseAsync(this DbConnection connection) + => _closeAsync(connection); + + private static Task CloseSync(DbConnection connection) + { + try + { + connection.Close(); + + return Task.CompletedTask; + } + catch (Exception e) + { + return Task.FromException(e); + } + } + } +} diff --git a/src/EFCore.Relational/Extensions/Internal/DbTransactionExtensions.cs b/src/EFCore.Relational/Extensions/Internal/DbTransactionExtensions.cs new file mode 100644 index 00000000000..697f2bbe88b --- /dev/null +++ b/src/EFCore.Relational/Extensions/Internal/DbTransactionExtensions.cs @@ -0,0 +1,100 @@ +// 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.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Data.Common +{ + internal static class DbTransactionExtensions + { + private static readonly Func _commitAsync; + private static readonly Func _rollbackAsync; + + static DbTransactionExtensions() + { + var commitAsync = typeof(DbTransaction) + .GetMethod("CommitAsync", new[] { typeof(CancellationToken) }); + if (commitAsync != null) + { + var transaction = Expression.Parameter(typeof(DbTransaction), "transaction"); + var cancellationToken = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); + + _commitAsync = Expression + .Lambda>( + Expression.Call(transaction, commitAsync, cancellationToken), + transaction, + cancellationToken) + .Compile(); + } + else + { + _commitAsync = CommitSync; + } + + var rollbackAsync = typeof(DbTransaction) + .GetMethod("RollbackAsync", new[] { typeof(CancellationToken) }); + if (rollbackAsync != null) + { + var transaction = Expression.Parameter(typeof(DbTransaction), "transaction"); + var cancellationToken = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); + + _rollbackAsync = Expression + .Lambda>( + Expression.Call(transaction, rollbackAsync, cancellationToken), + transaction, + cancellationToken) + .Compile(); + } + else + { + _rollbackAsync = RollbackSync; + } + } + + public static Task CommitAsync(this DbTransaction transaction, CancellationToken cancellationToken) + => _commitAsync(transaction, cancellationToken); + + private static Task CommitSync(DbTransaction transaction, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + + try + { + transaction.Commit(); + + return Task.CompletedTask; + } + catch (Exception e) + { + return Task.FromException(e); + } + } + + public static Task RollbackAsync(this DbTransaction transaction, CancellationToken cancellationToken) + => _rollbackAsync(transaction, cancellationToken); + + private static Task RollbackSync(DbTransaction transaction, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + + try + { + transaction.Rollback(); + + return Task.CompletedTask; + } + catch (Exception e) + { + return Task.FromException(e); + } + } + } +} diff --git a/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs b/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs index a08e0f542b4..4ac6c5c878e 100644 --- a/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/RelationalQueryFilterDefiningQueryRewritingConvention.cs @@ -2,8 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; namespace Microsoft.EntityFrameworkCore.Metadata.Conventions diff --git a/src/EFCore.Relational/Metadata/Internal/Sequence.cs b/src/EFCore.Relational/Metadata/Internal/Sequence.cs index df7ae0cb3f1..1161ea38060 100644 --- a/src/EFCore.Relational/Metadata/Internal/Sequence.cs +++ b/src/EFCore.Relational/Metadata/Internal/Sequence.cs @@ -601,7 +601,7 @@ private static string ExtractValue(string value, ref int position) end = value.IndexOf('\'', end + 2); } - var extracted = value[position..end].Replace("''", "'"); + var extracted = value.Substring(position, end - position).Replace("''", "'"); position = end + 1; return extracted.Length == 0 ? null : extracted; diff --git a/src/EFCore.Relational/Storage/RelationalCommand.cs b/src/EFCore.Relational/Storage/RelationalCommand.cs index 59fce60947f..eb552b6483a 100644 --- a/src/EFCore.Relational/Storage/RelationalCommand.cs +++ b/src/EFCore.Relational/Storage/RelationalCommand.cs @@ -142,7 +142,7 @@ private static async Task CleanupCommandAsync( IRelationalConnection connection) { command.Parameters.Clear(); - await command.DisposeAsync(); + await command.DisposeAsyncIfAvailable(); await connection.CloseAsync(); } diff --git a/src/EFCore.Relational/Storage/RelationalConnection.cs b/src/EFCore.Relational/Storage/RelationalConnection.cs index d1dbb5aa3c4..6d33005c00c 100644 --- a/src/EFCore.Relational/Storage/RelationalConnection.cs +++ b/src/EFCore.Relational/Storage/RelationalConnection.cs @@ -778,7 +778,7 @@ public virtual async ValueTask DisposeAsync() if (_connectionOwned && _connection != null) { - await DbConnection.DisposeAsync(); + await DbConnection.DisposeAsyncIfAvailable(); _connection = null; _openedCount = 0; } diff --git a/src/EFCore.Relational/Storage/RelationalDataReader.cs b/src/EFCore.Relational/Storage/RelationalDataReader.cs index 279188955ca..ef6dc710cd3 100644 --- a/src/EFCore.Relational/Storage/RelationalDataReader.cs +++ b/src/EFCore.Relational/Storage/RelationalDataReader.cs @@ -166,9 +166,9 @@ public virtual async ValueTask DisposeAsync() if (!interceptionResult.IsSuppressed) { - await _reader.DisposeAsync(); + await _reader.DisposeAsyncIfAvailable(); _command.Parameters.Clear(); - await _command.DisposeAsync(); + await _command.DisposeAsyncIfAvailable(); await _connection.CloseAsync(); } } diff --git a/src/EFCore.Relational/Storage/RelationalTransaction.cs b/src/EFCore.Relational/Storage/RelationalTransaction.cs index 0b1aadaa8c3..f32c3c5f3b4 100644 --- a/src/EFCore.Relational/Storage/RelationalTransaction.cs +++ b/src/EFCore.Relational/Storage/RelationalTransaction.cs @@ -305,7 +305,7 @@ public virtual async ValueTask DisposeAsync() if (_transactionOwned) { - await _dbTransaction.DisposeAsync(); + await _dbTransaction.DisposeAsyncIfAvailable(); Logger.TransactionDisposed( Connection, diff --git a/src/EFCore.SqlServer.NTS/EFCore.SqlServer.NTS.csproj b/src/EFCore.SqlServer.NTS/EFCore.SqlServer.NTS.csproj index c5b9a094107..ee1ad97f7f3 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.1 + netstandard2.0 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 73cf7177bb2..35dfa22de64 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.SqlServer Microsoft.EntityFrameworkCore.SqlServer diff --git a/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs b/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs index 8b83926f84f..6ae1b6db53c 100644 --- a/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs +++ b/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs @@ -202,7 +202,7 @@ private static Func GenerateSchemaFilter(IReadOnlyList s var schemaFilterBuilder = new StringBuilder(); schemaFilterBuilder.Append(s); schemaFilterBuilder.Append(" IN ("); - schemaFilterBuilder.AppendJoin(", ", schemas.Select(EscapeLiteral)); + schemaFilterBuilder.Append(string.Join(", ", schemas.Select(EscapeLiteral))); schemaFilterBuilder.Append(")"); return schemaFilterBuilder.ToString(); }) @@ -262,7 +262,7 @@ private static Func GenerateTableFilter( { tableFilterBuilder.Append(t); tableFilterBuilder.Append(" IN ("); - tableFilterBuilder.AppendJoin(", ", tablesWithoutSchema.Select(e => EscapeLiteral(e.Table))); + tableFilterBuilder.Append(string.Join(", ", tablesWithoutSchema.Select(e => EscapeLiteral(e.Table)))); tableFilterBuilder.Append(")"); } @@ -276,13 +276,13 @@ private static Func GenerateTableFilter( tableFilterBuilder.Append(t); tableFilterBuilder.Append(" IN ("); - tableFilterBuilder.AppendJoin(", ", tablesWithSchema.Select(e => EscapeLiteral(e.Table))); + tableFilterBuilder.Append(string.Join(", ", tablesWithSchema.Select(e => EscapeLiteral(e.Table)))); tableFilterBuilder.Append(") AND ("); tableFilterBuilder.Append(s); tableFilterBuilder.Append(" + N'.' + "); tableFilterBuilder.Append(t); tableFilterBuilder.Append(") IN ("); - tableFilterBuilder.AppendJoin(", ", tablesWithSchema.Select(e => EscapeLiteral($"{e.Schema}.{e.Table}"))); + tableFilterBuilder.Append(string.Join(", ", tablesWithSchema.Select(e => EscapeLiteral($"{e.Schema}.{e.Table}")))); tableFilterBuilder.Append(")"); } } diff --git a/src/EFCore.Sqlite.Core/EFCore.Sqlite.Core.csproj b/src/EFCore.Sqlite.Core/EFCore.Sqlite.Core.csproj index f8cec9a9c03..ec3db282304 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.1 + netstandard2.0 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 e2708d6f2c1..37564029493 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.1 + netstandard2.0 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 0163f33a067..3a5829057f8 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore.Sqlite $(PackageTags);SQLite diff --git a/src/EFCore.Sqlite/lib/netstandard2.1/_._ b/src/EFCore.Sqlite/lib/netstandard2.0/_._ similarity index 100% rename from src/EFCore.Sqlite/lib/netstandard2.1/_._ rename to src/EFCore.Sqlite/lib/netstandard2.0/_._ diff --git a/src/EFCore.Tools/lib/netstandard2.1/_._ b/src/EFCore.Tools/lib/netstandard2.0/_._ similarity index 100% rename from src/EFCore.Tools/lib/netstandard2.1/_._ rename to src/EFCore.Tools/lib/netstandard2.0/_._ diff --git a/src/EFCore/EFCore.csproj b/src/EFCore/EFCore.csproj index c719f4aff21..748edb763fa 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.1 + netstandard2.0 3.6 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore @@ -22,6 +22,8 @@ Microsoft.EntityFrameworkCore.DbSet + + diff --git a/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs b/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs index 85ae1756900..5d003dd3f04 100644 --- a/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs +++ b/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -24,6 +23,7 @@ public abstract class NonNullableConventionBase : IModelFinalizedConvention private const string StateAnnotationName = "NonNullableConventionState"; private const string NullableAttributeFullName = "System.Runtime.CompilerServices.NullableAttribute"; private const string NullableContextAttributeFullName = "System.Runtime.CompilerServices.NullableContextAttribute"; + private const string MaybeNullAttributeFullName = "System.Diagnostics.CodeAnalysis.MaybeNullAttribute"; /// /// Creates a new instance of . @@ -59,8 +59,9 @@ protected virtual bool IsNonNullableReferenceType( // First check for [MaybeNull] on the return value. If it exists, the member is nullable. var isMaybeNull = memberInfo switch { - FieldInfo f => f.GetCustomAttribute() != null, - PropertyInfo p => p.GetMethod?.ReturnParameter?.GetCustomAttribute() != null, + FieldInfo f => f.CustomAttributes.Any(a => a.AttributeType.FullName == MaybeNullAttributeFullName), + PropertyInfo p => p.GetMethod?.ReturnParameter?.CustomAttributes + .FirstOrDefault(a => a.AttributeType.FullName == MaybeNullAttributeFullName) != null, _ => false }; diff --git a/src/EFCore/Metadata/Conventions/QueryFilterDefiningQueryRewritingConvention.cs b/src/EFCore/Metadata/Conventions/QueryFilterDefiningQueryRewritingConvention.cs index 152b90774b3..5efd42251b3 100644 --- a/src/EFCore/Metadata/Conventions/QueryFilterDefiningQueryRewritingConvention.cs +++ b/src/EFCore/Metadata/Conventions/QueryFilterDefiningQueryRewritingConvention.cs @@ -2,8 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Query.Internal; diff --git a/src/EFCore/Metadata/Internal/ClrCollectionAccessor.cs b/src/EFCore/Metadata/Internal/ClrCollectionAccessor.cs index 8ae71c560e6..720aea81f45 100644 --- a/src/EFCore/Metadata/Internal/ClrCollectionAccessor.cs +++ b/src/EFCore/Metadata/Internal/ClrCollectionAccessor.cs @@ -197,9 +197,16 @@ public virtual bool Remove(object entity, object value) return false; case SortedSet sortedSet: - return sortedSet.TryGetValue((TElement)value, out var found) - && ReferenceEquals(found, value) - && sortedSet.Remove(found); + foreach (var item in sortedSet) + { + if (ReferenceEquals(item, value)) + { + sortedSet.Remove(item); + return true; + } + } + + return false; default: return collection?.Remove((TElement)value) ?? false; } @@ -230,8 +237,15 @@ private static bool Contains(ICollection collection, object value) return false; case SortedSet sortedSet: - return sortedSet.TryGetValue((TElement)value, out var found) - && ReferenceEquals(found, value); + foreach (var element in sortedSet) + { + if (ReferenceEquals(element, value)) + { + return true; + } + } + + return false; default: return collection?.Contains((TElement)value) == true; } diff --git a/src/EFCore/Metadata/Internal/IndexExtensions.cs b/src/EFCore/Metadata/Internal/IndexExtensions.cs index a2c265ee7e3..b14e89be5f5 100644 --- a/src/EFCore/Metadata/Internal/IndexExtensions.cs +++ b/src/EFCore/Metadata/Internal/IndexExtensions.cs @@ -54,12 +54,12 @@ public static string ToDebugString([NotNull] this IIndex index, bool singleLine } builder - .AppendJoin( + .Append(string.Join( ", ", index.Properties.Select( p => singleLine ? p.DeclaringEntityType.DisplayName() + "." + p.Name - : p.Name)); + : p.Name))); if (index.IsUnique) { diff --git a/src/EFCore/Metadata/Internal/KeyExtensions.cs b/src/EFCore/Metadata/Internal/KeyExtensions.cs index 7cc1e1ba623..f61c62f6afd 100644 --- a/src/EFCore/Metadata/Internal/KeyExtensions.cs +++ b/src/EFCore/Metadata/Internal/KeyExtensions.cs @@ -70,11 +70,11 @@ public static string ToDebugString([NotNull] this IKey key, bool singleLine = tr builder.Append("Key: "); } - builder.AppendJoin( + builder.Append(string.Join( ", ", key.Properties.Select( p => singleLine ? p.DeclaringEntityType.DisplayName() + "." + p.Name - : p.Name)); + : p.Name))); if (key.IsPrimaryKey()) { diff --git a/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs b/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs index e5b7932ddc9..a5a06e67c3e 100644 --- a/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs +++ b/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs @@ -1,7 +1,7 @@ // 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.Diagnostics.CodeAnalysis; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Shared/Check.cs b/src/Shared/Check.cs index c974f3e3915..e65c35786ec 100644 --- a/src/Shared/Check.cs +++ b/src/Shared/Check.cs @@ -95,7 +95,7 @@ public static IReadOnlyList HasNoNulls(IReadOnlyList value, [InvokerPar } [Conditional("DEBUG")] - public static void DebugAssert([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool condition, string message) + public static void DebugAssert(bool condition, string message) { if (!condition) { diff --git a/src/ef/Commands/ProjectCommandBase.cs b/src/ef/Commands/ProjectCommandBase.cs index 661ae7588c9..4d026c4ccbd 100644 --- a/src/ef/Commands/ProjectCommandBase.cs +++ b/src/ef/Commands/ProjectCommandBase.cs @@ -1,6 +1,7 @@ // 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.IO; using System.Reflection; using Microsoft.DotNet.Cli.CommandLine; @@ -47,14 +48,22 @@ protected IOperationExecutor CreateExecutor() try { #if NET461 - return new AppDomainOperationExecutor( - _assembly.Value(), - _startupAssembly.Value(), - _projectDir.Value(), - _dataDir.Value(), - _rootNamespace.Value(), - _language.Value()); -#elif NETCOREAPP2_0 + try + { + return new AppDomainOperationExecutor( + _assembly.Value(), + _startupAssembly.Value(), + _projectDir.Value(), + _dataDir.Value(), + _rootNamespace.Value(), + _language.Value()); + } + catch (MissingMethodException) // NB: Thrown with EF Core 3.1 + { + } +#elif !NETCOREAPP2_0 +#error target frameworks need to be updated. +#endif return new ReflectionOperationExecutor( _assembly.Value(), _startupAssembly.Value(), @@ -62,9 +71,6 @@ protected IOperationExecutor CreateExecutor() _dataDir.Value(), _rootNamespace.Value(), _language.Value()); -#else -#error target frameworks need to be updated. -#endif } catch (FileNotFoundException ex) when (new AssemblyName(ex.FileName).Name == OperationExecutorBase.DesignAssemblyName)