diff --git a/Directory.Packages.props b/Directory.Packages.props
index 2a88b69da3e..5975e2b9a33 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -36,7 +36,7 @@
-
+
@@ -51,14 +51,14 @@
-
+
-
-
+
+
diff --git a/NuGet.config b/NuGet.config
index 305904c0315..b24702052c1 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,7 +4,7 @@
-
+
@@ -21,7 +21,7 @@
-
+
diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml
index d56ef44140b..85b9fbab9e4 100644
--- a/azure-pipelines-public.yml
+++ b/azure-pipelines-public.yml
@@ -93,7 +93,7 @@ stages:
- job: macOS
enablePublishTestResults: true
pool:
- vmImage: macOS-12
+ vmImage: macOS-13
variables:
# Rely on task Arcade injects, not auto-injected build step.
- skipComponentGovernanceDetection: true
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 8741f1c3b71..530b57da6a1 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -139,7 +139,7 @@ extends:
- job: macOS
pool:
name: Azure Pipelines
- image: macOS-12
+ image: macOS-13
os: macOS
variables:
# Rely on task Arcade injects, not auto-injected build step.
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 24a836cec81..3fff94bc548 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,83 +1,83 @@
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9d5a6a9aa463d6d10b0b0ba6d5982cc82f363dc3
+ c8acea22626efab11c13778c028975acdc34678f
-
+
https://github.com/dotnet/arcade
- 3c393bbd85ae16ddddba20d0b75035b0c6f1a52d
+ b41381d5cd633471265e9cd72e933a7048e03062
-
+
https://github.com/dotnet/arcade
- 3c393bbd85ae16ddddba20d0b75035b0c6f1a52d
+ b41381d5cd633471265e9cd72e933a7048e03062
-
+
https://github.com/dotnet/arcade
- 3c393bbd85ae16ddddba20d0b75035b0c6f1a52d
+ b41381d5cd633471265e9cd72e933a7048e03062
diff --git a/eng/Versions.props b/eng/Versions.props
index 858be25e405..dc4ee10c83a 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,6 +1,6 @@
- 9.0.0
+ 9.0.1
rtm
@@ -17,24 +17,24 @@
False
- 9.0.0
- 9.0.0
- 9.0.0
- 9.0.0
- 9.0.0
- 9.0.0
- 9.0.0
- 9.0.0-rtm.24528.9
- 9.0.0
- 9.0.0
- 9.0.0
- 9.0.0-rtm.24528.9
- 9.0.0
- 9.0.0
- 9.0.0
+ 9.0.1
+ 9.0.1
+ 9.0.1
+ 9.0.1
+ 9.0.1
+ 9.0.1
+ 9.0.1
+ 9.0.1-servicing.24610.10
+ 9.0.1
+ 9.0.1
+ 9.0.1
+ 9.0.1-servicing.24610.10
+ 9.0.1
+ 9.0.1
+ 9.0.1
- 9.0.0-beta.24516.2
+ 9.0.0-beta.24572.2
17.8.3
diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1
index aab40de3fd9..4f0546dce12 100644
--- a/eng/common/sdk-task.ps1
+++ b/eng/common/sdk-task.ps1
@@ -64,7 +64,7 @@ try {
$GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty
}
if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) {
- $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.10.0-pre.4.0" -MemberType NoteProperty
+ $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.12.0" -MemberType NoteProperty
}
if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") {
$xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index 22954477a57..aa94fb17459 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -383,8 +383,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
# If the version of msbuild is going to be xcopied,
# use this version. Version matches a package here:
- # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/Microsoft.DotNet.Arcade.MSBuild.Xcopy/versions/17.10.0-pre.4.0
- $defaultXCopyMSBuildVersion = '17.10.0-pre.4.0'
+ # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/Microsoft.DotNet.Arcade.MSBuild.Xcopy/versions/17.12.0
+ $defaultXCopyMSBuildVersion = '17.12.0'
if (!$vsRequirements) {
if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') {
diff --git a/global.json b/global.json
index 9cf9fded9e5..90650c26b0b 100644
--- a/global.json
+++ b/global.json
@@ -1,11 +1,11 @@
{
"sdk": {
- "version": "9.0.100-rc.2.24474.11",
+ "version": "9.0.100",
"allowPrerelease": true,
"rollForward": "latestMajor"
},
"tools": {
- "dotnet": "9.0.100-rc.2.24474.11",
+ "dotnet": "9.0.100",
"runtimes": {
"dotnet": [
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
@@ -13,7 +13,7 @@
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24516.2",
- "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24516.2"
+ "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24572.2",
+ "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24572.2"
}
}
diff --git a/src/EFCore.Cosmos/Extensions/DistanceFunction.cs b/src/EFCore.Cosmos/Extensions/DistanceFunction.cs
deleted file mode 100644
index 2df582e5ca1..00000000000
--- a/src/EFCore.Cosmos/Extensions/DistanceFunction.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.Serialization;
-
-// ReSharper disable once CheckNamespace
-namespace Microsoft.Azure.Cosmos;
-
-///
-/// Defines the distance function for a vector index specification in the Azure Cosmos DB service.
-/// Warning: this type will be replaced by the type from the Cosmos SDK, when it is available.
-///
-///
-/// for usage.
-[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
-public enum DistanceFunction
-{
- ///
- /// Represents the Euclidean distance function.
- ///
- [EnumMember(Value = "euclidean")]
- Euclidean,
-
- ///
- /// Represents the cosine distance function.
- ///
- [EnumMember(Value = "cosine")]
- Cosine,
-
- ///
- /// Represents the dot product distance function.
- ///
- [EnumMember(Value = "dotproduct")]
- DotProduct,
-}
diff --git a/src/EFCore.Cosmos/Extensions/Embedding.cs b/src/EFCore.Cosmos/Extensions/Embedding.cs
deleted file mode 100644
index e46c274d887..00000000000
--- a/src/EFCore.Cosmos/Extensions/Embedding.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-
-// ReSharper disable once CheckNamespace
-namespace Microsoft.Azure.Cosmos;
-
-[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
-internal class Embedding : IEquatable
-{
- public string? Path { get; set; }
- public VectorDataType DataType { get; set; }
- public int Dimensions { get; set; }
- public DistanceFunction DistanceFunction { get; set; }
-
- public bool Equals(Embedding? that)
- => Equals(Path, that?.Path) && Equals(DataType, that?.DataType) && Equals(Dimensions, that.Dimensions);
-}
diff --git a/src/EFCore.Cosmos/Extensions/VectorDataType.cs b/src/EFCore.Cosmos/Extensions/VectorDataType.cs
deleted file mode 100644
index cb547fd1b3a..00000000000
--- a/src/EFCore.Cosmos/Extensions/VectorDataType.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.Serialization;
-
-// ReSharper disable once CheckNamespace
-namespace Microsoft.Azure.Cosmos;
-
-///
-/// Defines the target data type of a vector index specification in the Azure Cosmos DB service.
-/// Warning: this type will be replaced by the type from the Cosmos SDK, when it is available.
-///
-[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
-public enum VectorDataType
-{
- ///
- /// Represents a 16-bit floating point data type.
- ///
- [EnumMember(Value = "float16")]
- Float16,
-
- ///
- /// Represents a 32-bit floating point data type.
- ///
- [EnumMember(Value = "float32")]
- Float32,
-
- ///
- /// Represents an unsigned 8-bit binary data type.
- ///
- [EnumMember(Value = "uint8")]
- Uint8,
-
- ///
- /// Represents a signed 8-bit binary data type.
- ///
- [EnumMember(Value = "int8")]
- Int8,
-}
diff --git a/src/EFCore.Cosmos/Extensions/VectorIndexPath.cs b/src/EFCore.Cosmos/Extensions/VectorIndexPath.cs
deleted file mode 100644
index 8a575c2c40f..00000000000
--- a/src/EFCore.Cosmos/Extensions/VectorIndexPath.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-
-// ReSharper disable once CheckNamespace
-namespace Microsoft.Azure.Cosmos;
-
-[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
-internal sealed class VectorIndexPath
-{
- public string? Path { get; set; }
- public VectorIndexType Type { get; set; }
-}
diff --git a/src/EFCore.Cosmos/Extensions/VectorIndexType.cs b/src/EFCore.Cosmos/Extensions/VectorIndexType.cs
deleted file mode 100644
index 88f71d32a5d..00000000000
--- a/src/EFCore.Cosmos/Extensions/VectorIndexType.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.Serialization;
-
-// ReSharper disable once CheckNamespace
-namespace Microsoft.Azure.Cosmos;
-
-///
-/// Defines the target index type of the vector index path specification in the Azure Cosmos DB service.
-/// Warning: this type will be replaced by the type from the Cosmos SDK, when it is available.
-///
-[Experimental(EFDiagnostics.CosmosVectorSearchExperimental)]
-public enum VectorIndexType
-{
- ///
- /// Represents a flat vector index type.
- ///
- [EnumMember(Value = "flat")]
- Flat,
-
- ///
- /// Represents a Disk ANN vector index type.
- ///
- [EnumMember(Value = "diskANN")]
- // ReSharper disable once InconsistentNaming
- DiskANN,
-
- ///
- /// Represents a quantized flat vector index type.
- ///
- [EnumMember(Value = "quantizedFlat")]
- QuantizedFlat,
-}
diff --git a/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs b/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs
index d9571fc2d05..6c63a1c718e 100644
--- a/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs
+++ b/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs
@@ -305,12 +305,6 @@ public static string NoReadItemQueryString(object? resourceId, object? partition
public static string NoSubqueryPushdown
=> GetString("NoSubqueryPushdown");
- ///
- /// Container configuration for embeddings is not yet supported by the Cosmos SDK. Instead, configure the container manually. See https://aka.ms/ef-cosmos-vectors for more information.
- ///
- public static string NoVectorContainerConfig
- => GetString("NoVectorContainerConfig");
-
///
/// The expression '{sqlExpression}' in the SQL tree does not have a type mapping assigned.
///
diff --git a/src/EFCore.Cosmos/Properties/CosmosStrings.resx b/src/EFCore.Cosmos/Properties/CosmosStrings.resx
index 171d85f852c..8f9a875524b 100644
--- a/src/EFCore.Cosmos/Properties/CosmosStrings.resx
+++ b/src/EFCore.Cosmos/Properties/CosmosStrings.resx
@@ -271,9 +271,6 @@
Azure Cosmos DB does not have an appropriate subquery for this translation.
-
- Container configuration for embeddings is not yet supported by the Cosmos SDK. Instead, configure the container manually. See https://aka.ms/ef-cosmos-vectors for more information.
-
The expression '{sqlExpression}' in the SQL tree does not have a type mapping assigned.
diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs
index 9b446a78152..7ad49bd00c4 100644
--- a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs
@@ -16,6 +16,9 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;
///
public class CosmosQueryableMethodTranslatingExpressionVisitor : QueryableMethodTranslatingExpressionVisitor
{
+ private static readonly bool UseOldBehavior35094 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue35094", out var enabled) && enabled;
+
private readonly CosmosQueryCompilationContext _queryCompilationContext;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private readonly ITypeMappingSource _typeMappingSource;
@@ -445,23 +448,29 @@ private ShapedQueryExpression CreateShapedQueryExpression(SelectExpression selec
///
protected override ShapedQueryExpression? TranslateAverage(ShapedQueryExpression source, LambdaExpression? selector, Type resultType)
{
- var selectExpression = (SelectExpression)source.QueryExpression;
- if (selectExpression.IsDistinct
- || selectExpression.Limit != null
- || selectExpression.Offset != null)
+ if (UseOldBehavior35094)
{
- return null;
- }
+ var selectExpression = (SelectExpression)source.QueryExpression;
+ if (selectExpression.IsDistinct
+ || selectExpression.Limit != null
+ || selectExpression.Offset != null)
+ {
+ return null;
+ }
- if (selector != null)
- {
- source = TranslateSelect(source, selector);
- }
+ if (selector != null)
+ {
+ source = TranslateSelect(source, selector);
+ }
- var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
- projection = _sqlExpressionFactory.Function("AVG", new[] { projection }, projection.Type, projection.TypeMapping);
+ var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
+ projection = _sqlExpressionFactory.Function("AVG", new[] { projection }, projection.Type, projection.TypeMapping);
- return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+ return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+
+ }
+
+ return TranslateAggregate(source, selector, resultType, "AVG");
}
///
@@ -843,24 +852,29 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
///
protected override ShapedQueryExpression? TranslateMax(ShapedQueryExpression source, LambdaExpression? selector, Type resultType)
{
- var selectExpression = (SelectExpression)source.QueryExpression;
- if (selectExpression.IsDistinct
- || selectExpression.Limit != null
- || selectExpression.Offset != null)
+ if (UseOldBehavior35094)
{
- return null;
- }
+ var selectExpression = (SelectExpression)source.QueryExpression;
+ if (selectExpression.IsDistinct
+ || selectExpression.Limit != null
+ || selectExpression.Offset != null)
+ {
+ return null;
+ }
- if (selector != null)
- {
- source = TranslateSelect(source, selector);
- }
+ if (selector != null)
+ {
+ source = TranslateSelect(source, selector);
+ }
- var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
+ var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
- projection = _sqlExpressionFactory.Function("MAX", new[] { projection }, resultType, projection.TypeMapping);
+ projection = _sqlExpressionFactory.Function("MAX", new[] { projection }, resultType, projection.TypeMapping);
- return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+ return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+ }
+
+ return TranslateAggregate(source, selector, resultType, "MAX");
}
///
@@ -871,24 +885,29 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
///
protected override ShapedQueryExpression? TranslateMin(ShapedQueryExpression source, LambdaExpression? selector, Type resultType)
{
- var selectExpression = (SelectExpression)source.QueryExpression;
- if (selectExpression.IsDistinct
- || selectExpression.Limit != null
- || selectExpression.Offset != null)
+ if (UseOldBehavior35094)
{
- return null;
- }
+ var selectExpression = (SelectExpression)source.QueryExpression;
+ if (selectExpression.IsDistinct
+ || selectExpression.Limit != null
+ || selectExpression.Offset != null)
+ {
+ return null;
+ }
- if (selector != null)
- {
- source = TranslateSelect(source, selector);
- }
+ if (selector != null)
+ {
+ source = TranslateSelect(source, selector);
+ }
- var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
+ var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
- projection = _sqlExpressionFactory.Function("MIN", new[] { projection }, resultType, projection.TypeMapping);
+ projection = _sqlExpressionFactory.Function("MIN", new[] { projection }, resultType, projection.TypeMapping);
- return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+ return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+ }
+
+ return TranslateAggregate(source, selector, resultType, "MIN");
}
///
@@ -1520,6 +1539,35 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
#endregion Queryable collection support
+ private ShapedQueryExpression? TranslateAggregate(ShapedQueryExpression source, LambdaExpression? selector, Type resultType, string functionName)
+ {
+ var selectExpression = (SelectExpression)source.QueryExpression;
+ if (selectExpression.IsDistinct
+ || selectExpression.Limit != null
+ || selectExpression.Offset != null)
+ {
+ return null;
+ }
+
+ if (selector != null)
+ {
+ source = TranslateSelect(source, selector);
+ }
+
+ if (!_subquery && resultType.IsNullableType())
+ {
+ // For nullable types, we want to return null from Max, Min, and Average, rather than throwing. See Issue #35094.
+ // Note that relational databases typically return null, which propagates. Cosmos will instead return no elements,
+ // and hence for Cosmos only we need to change no elements into null.
+ source = source.UpdateResultCardinality(ResultCardinality.SingleOrDefault);
+ }
+
+ var projection = (SqlExpression)selectExpression.GetMappedProjection(new ProjectionMember());
+ projection = _sqlExpressionFactory.Function(functionName, [projection], resultType, _typeMappingSource.FindMapping(resultType));
+
+ return AggregateResultShaper(source, projection, throwOnNullResult: true, resultType);
+ }
+
private bool TryApplyPredicate(ShapedQueryExpression source, LambdaExpression predicate)
{
var select = (SelectExpression)source.QueryExpression;
diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs
index a5c89b6b37d..9f2793deeaa 100644
--- a/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs
+++ b/src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs
@@ -272,17 +272,14 @@ private static async Task CreateContainerIfNotExistsOnceAsync(
AnalyticalStoreTimeToLiveInSeconds = parameters.AnalyticalStoreTimeToLiveInSeconds,
};
- // TODO: Enable these once they are available in the Cosmos SDK. See #33783.
if (embeddings.Any())
{
- throw new InvalidOperationException(CosmosStrings.NoVectorContainerConfig);
- //containerProperties.VectorEmbeddingPolicy = new VectorEmbeddingPolicy(embeddings);
+ containerProperties.VectorEmbeddingPolicy = new VectorEmbeddingPolicy(embeddings);
}
if (vectorIndexes.Any())
{
- throw new InvalidOperationException(CosmosStrings.NoVectorContainerConfig);
- //containerProperties.IndexingPolicy = new IndexingPolicy { VectorIndexes = vectorIndexes };
+ containerProperties.IndexingPolicy = new IndexingPolicy { VectorIndexes = vectorIndexes };
}
var response = await wrapper.Client.GetDatabase(wrapper._databaseId).CreateContainerIfNotExistsAsync(
diff --git a/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs b/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs
index 2015337b4e6..b797f8a4add 100644
--- a/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs
+++ b/src/EFCore.Design/Design/Internal/AppServiceProviderFactory.cs
@@ -55,23 +55,6 @@ public virtual IServiceProvider Create(string[] args)
return null;
}
- var aspnetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
- var dotnetEnvironment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
- var environment = aspnetCoreEnvironment
- ?? dotnetEnvironment
- ?? "Development";
- if (aspnetCoreEnvironment == null)
- {
- Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", environment);
- }
-
- if (dotnetEnvironment == null)
- {
- Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", environment);
- }
-
- _reporter.WriteVerbose(DesignStrings.UsingEnvironment(environment));
-
try
{
var services = serviceProviderFactory(args);
diff --git a/src/EFCore.Design/Design/Internal/DbContextOperations.cs b/src/EFCore.Design/Design/Internal/DbContextOperations.cs
index da44b15b283..761579c8bdb 100644
--- a/src/EFCore.Design/Design/Internal/DbContextOperations.cs
+++ b/src/EFCore.Design/Design/Internal/DbContextOperations.cs
@@ -503,6 +503,23 @@ private IDictionary> FindContextTypes(string? name = null,
{
_reporter.WriteVerbose(DesignStrings.FindingContexts);
+ var aspnetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
+ var dotnetEnvironment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
+ var environment = aspnetCoreEnvironment
+ ?? dotnetEnvironment
+ ?? "Development";
+ if (aspnetCoreEnvironment == null)
+ {
+ Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", environment);
+ }
+
+ if (dotnetEnvironment == null)
+ {
+ Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", environment);
+ }
+
+ _reporter.WriteVerbose(DesignStrings.UsingEnvironment(environment));
+
var contexts = new Dictionary?>();
try
diff --git a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs
index c05c73c46a3..0b1f48c5275 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs
@@ -81,6 +81,7 @@ private enum Id
NonTransactionalMigrationOperationWarning,
AcquiringMigrationLock,
MigrationsUserTransactionWarning,
+ ModelSnapshotNotFound,
// Query events
QueryClientEvaluationWarning = CoreEventId.RelationalBaseId + 500,
@@ -778,6 +779,19 @@ private static EventId MakeMigrationsId(Id id)
///
public static readonly EventId MigrationsUserTransactionWarning = MakeMigrationsId(Id.MigrationsUserTransactionWarning);
+ ///
+ /// Model snapshot was not found.
+ ///
+ ///
+ ///
+ /// This event is in the category.
+ ///
+ ///
+ /// This event uses the payload when used with a .
+ ///
+ ///
+ public static readonly EventId ModelSnapshotNotFound = MakeMigrationsId(Id.ModelSnapshotNotFound);
+
private static readonly string _queryPrefix = DbLoggerCategory.Query.Name + ".";
private static EventId MakeQueryId(Id id)
diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
index 177b7e90bba..acecc79ca01 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
@@ -2343,6 +2343,77 @@ private static string PendingModelChanges(EventDefinitionBase definition, EventD
return d.GenerateMessage(p.ContextType.ShortDisplayName());
}
+ ///
+ /// Logs for the event.
+ ///
+ /// The diagnostics logger to use.
+ /// The type being used.
+ public static void NonDeterministicModel(
+ this IDiagnosticsLogger diagnostics,
+ Type contextType)
+ {
+ var definition = RelationalResources.LogNonDeterministicModel(diagnostics);
+
+ if (diagnostics.ShouldLog(definition))
+ {
+ definition.Log(diagnostics, contextType.ShortDisplayName());
+ }
+
+ if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = new DbContextTypeEventData(
+ definition,
+ NonDeterministicModel,
+ contextType);
+
+ diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+ }
+ }
+
+ private static string NonDeterministicModel(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (DbContextTypeEventData)payload;
+ return d.GenerateMessage(p.ContextType.ShortDisplayName());
+ }
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The diagnostics logger to use.
+ /// The migrator.
+ /// The assembly in which migrations are stored.
+ public static void ModelSnapshotNotFound(
+ this IDiagnosticsLogger diagnostics,
+ IMigrator migrator,
+ IMigrationsAssembly migrationsAssembly)
+ {
+ var definition = RelationalResources.LogNoModelSnapshotFound(diagnostics);
+
+ if (diagnostics.ShouldLog(definition))
+ {
+ definition.Log(diagnostics, migrationsAssembly.Assembly.GetName().Name!);
+ }
+
+ if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = new MigrationAssemblyEventData(
+ definition,
+ ModelSnapshotNotFound,
+ migrator,
+ migrationsAssembly);
+
+ diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+ }
+ }
+
+ private static string ModelSnapshotNotFound(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (MigrationAssemblyEventData)payload;
+ return d.GenerateMessage(p.MigrationsAssembly.Assembly.GetName().Name!);
+ }
+
///
/// Logs for the event.
///
diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs
index 762172c8944..9634f027bf7 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs
@@ -374,7 +374,7 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
[EntityFrameworkInternal]
- public EventDefinitionBase? LogMigrationsUserTransactionWarning;
+ public EventDefinitionBase? LogMigrationsUserTransaction;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -673,6 +673,24 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
[EntityFrameworkInternal]
public EventDefinitionBase? LogPendingModelChanges;
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ [EntityFrameworkInternal]
+ public EventDefinitionBase? LogNonDeterministicModel;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ [EntityFrameworkInternal]
+ public EventDefinitionBase? LogNoModelSnapshotFound;
+
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs
index 3c1c1b2304e..9aa9d933f9a 100644
--- a/src/EFCore.Relational/Migrations/HistoryRepository.cs
+++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs
@@ -219,8 +219,7 @@ async Task IHistoryRepository.CreateIfNotExistsAsync(CancellationToken can
private IReadOnlyList GetCreateIfNotExistsCommands()
=> Dependencies.MigrationsSqlGenerator.Generate([new SqlOperation
{
- Sql = GetCreateIfNotExistsScript(),
- SuppressTransaction = true
+ Sql = GetCreateIfNotExistsScript()
}]);
///
diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs
index 4380d89fd82..ea758d2c634 100644
--- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs
+++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs
@@ -3,6 +3,7 @@
using System.Transactions;
using Microsoft.EntityFrameworkCore.Diagnostics.Internal;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace Microsoft.EntityFrameworkCore.Migrations.Internal;
@@ -93,24 +94,7 @@ public Migrator(
public virtual void Migrate(string? targetMigration)
{
var useTransaction = _connection.CurrentTransaction is null;
- if (!useTransaction
- && _executionStrategy.RetriesOnFailure)
- {
- throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);
- }
-
- if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore
- && HasPendingModelChanges())
- {
- _logger.PendingModelChangesWarning(_currentContext.Context.GetType());
- }
-
- if (!useTransaction)
- {
- _logger.MigrationsUserTransactionWarning();
- }
-
- _logger.MigrateUsingConnection(this, _connection);
+ ValidateMigrations(useTransaction);
using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled);
@@ -235,24 +219,7 @@ public virtual async Task MigrateAsync(
CancellationToken cancellationToken = default)
{
var useTransaction = _connection.CurrentTransaction is null;
- if (!useTransaction
- && _executionStrategy.RetriesOnFailure)
- {
- throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);
- }
-
- if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore
- && HasPendingModelChanges())
- {
- _logger.PendingModelChangesWarning(_currentContext.Context.GetType());
- }
-
- if (!useTransaction)
- {
- _logger.MigrationsUserTransactionWarning();
- }
-
- _logger.MigrateUsingConnection(this, _connection);
+ ValidateMigrations(useTransaction);
using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled);
@@ -382,6 +349,48 @@ await _migrationCommandExecutor.ExecuteNonQueryAsync(
}
}
+ private void ValidateMigrations(bool useTransaction)
+ {
+ if (!useTransaction
+ && _executionStrategy.RetriesOnFailure)
+ {
+ throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);
+ }
+
+ if (_migrationsAssembly.Migrations.Count == 0)
+ {
+ _logger.MigrationsNotFound(this, _migrationsAssembly);
+ }
+ else if (_migrationsAssembly.ModelSnapshot == null)
+ {
+ _logger.ModelSnapshotNotFound(this, _migrationsAssembly);
+ }
+ else if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore
+ && HasPendingModelChanges())
+ {
+ var modelSource = (ModelSource)_currentContext.Context.GetService();
+#pragma warning disable EF1001 // Internal EF Core API usage.
+ var newDesignTimeModel = modelSource.CreateModel(
+ _currentContext.Context, _currentContext.Context.GetService(), designTime: true);
+#pragma warning restore EF1001 // Internal EF Core API usage.
+ if (_migrationsModelDiffer.HasDifferences(newDesignTimeModel.GetRelationalModel(), _designTimeModel.Model.GetRelationalModel()))
+ {
+ _logger.NonDeterministicModel(_currentContext.Context.GetType());
+ }
+ else
+ {
+ _logger.PendingModelChangesWarning(_currentContext.Context.GetType());
+ }
+ }
+
+ if (!useTransaction)
+ {
+ _logger.MigrationsUserTransactionWarning();
+ }
+
+ _logger.MigrateUsingConnection(this, _connection);
+ }
+
private IEnumerable<(string, Func>)> GetMigrationCommandLists(MigratorData parameters)
{
var migrationsToApply = parameters.AppliedMigrations;
@@ -449,10 +458,6 @@ protected virtual void PopulateMigrations(
var appliedMigrations = new Dictionary();
var unappliedMigrations = new Dictionary();
var appliedMigrationEntrySet = new HashSet(appliedMigrationEntries, StringComparer.OrdinalIgnoreCase);
- if (_migrationsAssembly.Migrations.Count == 0)
- {
- _logger.MigrationsNotFound(this, _migrationsAssembly);
- }
foreach (var (key, typeInfo) in _migrationsAssembly.Migrations)
{
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
index 731c62c4ec2..5bbbd42c9d0 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
+++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
@@ -3429,11 +3429,11 @@ public static EventDefinition LogMigrationAttributeMissingWarning(IDiagn
///
public static EventDefinition LogMigrationsUserTransaction(IDiagnosticsLogger logger)
{
- var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransactionWarning;
+ var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransaction;
if (definition == null)
{
definition = NonCapturingLazyInitializer.EnsureInitialized(
- ref ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransactionWarning,
+ ref ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransaction,
logger,
static logger => new EventDefinition(
logger.Options,
@@ -3572,7 +3572,7 @@ public static EventDefinition LogNoMigrationsApplied(IDiagnosticsLogger logger)
}
///
- /// No migrations were found in assembly '{migrationsAssembly}'.
+ /// No migrations were found in assembly '{migrationsAssembly}'. A migration needs to be added before the database can be updated.
///
public static EventDefinition LogNoMigrationsFound(IDiagnosticsLogger logger)
{
@@ -3585,7 +3585,7 @@ public static EventDefinition LogNoMigrationsFound(IDiagnosticsLogger lo
static logger => new EventDefinition(
logger.Options,
RelationalEventId.MigrationsNotFound,
- LogLevel.Debug,
+ LogLevel.Information,
"RelationalEventId.MigrationsNotFound",
level => LoggerMessage.Define(
level,
@@ -3596,6 +3596,56 @@ public static EventDefinition LogNoMigrationsFound(IDiagnosticsLogger lo
return (EventDefinition)definition;
}
+ ///
+ /// Model snapshot was not found in assembly '{migrationsAssembly}'. Skipping pending model changes check.
+ ///
+ public static EventDefinition LogNoModelSnapshotFound(IDiagnosticsLogger logger)
+ {
+ var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogNoModelSnapshotFound;
+ if (definition == null)
+ {
+ definition = NonCapturingLazyInitializer.EnsureInitialized(
+ ref ((RelationalLoggingDefinitions)logger.Definitions).LogNoModelSnapshotFound,
+ logger,
+ static logger => new EventDefinition(
+ logger.Options,
+ RelationalEventId.ModelSnapshotNotFound,
+ LogLevel.Information,
+ "RelationalEventId.ModelSnapshotNotFound",
+ level => LoggerMessage.Define(
+ level,
+ RelationalEventId.ModelSnapshotNotFound,
+ _resourceManager.GetString("LogNoModelSnapshotFound")!)));
+ }
+
+ return (EventDefinition)definition;
+ }
+
+ ///
+ /// The model for context '{contextType}' changes each time it is built. This is usually caused by dynamic values used in a 'HasData' call (e.g. `new DateTime()`, `Guid.NewGuid()`). Add a new migration and examine its contents to locate the cause, and replace the dynamic call with a static, hardcoded value. See https://aka.ms/efcore-docs-pending-changes.
+ ///
+ public static EventDefinition LogNonDeterministicModel(IDiagnosticsLogger logger)
+ {
+ var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogNonDeterministicModel;
+ if (definition == null)
+ {
+ definition = NonCapturingLazyInitializer.EnsureInitialized(
+ ref ((RelationalLoggingDefinitions)logger.Definitions).LogNonDeterministicModel,
+ logger,
+ static logger => new EventDefinition(
+ logger.Options,
+ RelationalEventId.PendingModelChangesWarning,
+ LogLevel.Error,
+ "RelationalEventId.PendingModelChangesWarning",
+ level => LoggerMessage.Define(
+ level,
+ RelationalEventId.PendingModelChangesWarning,
+ _resourceManager.GetString("LogNonDeterministicModel")!)));
+ }
+
+ return (EventDefinition)definition;
+ }
+
///
/// The migration operation '{operation}' from migration '{migration}' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
///
@@ -3610,7 +3660,7 @@ public static EventDefinition LogNonTransactionalMigrationOperat
static logger => new EventDefinition(
logger.Options,
RelationalEventId.NonTransactionalMigrationOperationWarning,
- LogLevel.Error,
+ LogLevel.Warning,
"RelationalEventId.NonTransactionalMigrationOperationWarning",
level => LoggerMessage.Define(
level,
@@ -3747,7 +3797,7 @@ public static EventDefinition LogOptionalDependentWithoutIdentifyingProp
}
///
- /// The model for context '{contextType}' has pending changes. Add a new migration before updating the database.
+ /// The model for context '{contextType}' has pending changes. Add a new migration before updating the database. See https://aka.ms/efcore-docs-pending-changes.
///
public static EventDefinition LogPendingModelChanges(IDiagnosticsLogger logger)
{
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx
index 104daf9dafb..2382f648428 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.resx
+++ b/src/EFCore.Relational/Properties/RelationalStrings.resx
@@ -811,12 +811,20 @@
Information RelationalEventId.MigrationsNotApplied
- No migrations were found in assembly '{migrationsAssembly}'.
- Debug RelationalEventId.MigrationsNotFound string
+ No migrations were found in assembly '{migrationsAssembly}'. A migration needs to be added before the database can be updated.
+ Information RelationalEventId.MigrationsNotFound string
+
+
+ Model snapshot was not found in assembly '{migrationsAssembly}'. Skipping pending model changes check.
+ Information RelationalEventId.ModelSnapshotNotFound string
+
+
+ The model for context '{contextType}' changes each time it is built. This is usually caused by dynamic values used in a 'HasData' call (e.g. `new DateTime()`, `Guid.NewGuid()`). Add a new migration and examine its contents to locate the cause, and replace the dynamic call with a static, hardcoded value. See https://aka.ms/efcore-docs-pending-changes.
+ Error RelationalEventId.PendingModelChangesWarning string
The migration operation '{operation}' from migration '{migration}' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
- Error RelationalEventId.NonTransactionalMigrationOperationWarning string string
+ Warning RelationalEventId.NonTransactionalMigrationOperationWarning string string
Opened connection to database '{database}' on server '{server}'.
@@ -839,7 +847,7 @@
Warning RelationalEventId.OptionalDependentWithoutIdentifyingPropertyWarning string
- The model for context '{contextType}' has pending changes. Add a new migration before updating the database.
+ The model for context '{contextType}' has pending changes. Add a new migration before updating the database. See https://aka.ms/efcore-docs-pending-changes.
Error RelationalEventId.PendingModelChangesWarning string
diff --git a/src/EFCore.Relational/Query/RelationalLiftableConstantProcessor.cs b/src/EFCore.Relational/Query/RelationalLiftableConstantProcessor.cs
index 2d0b9fa8c0c..32445d46a71 100644
--- a/src/EFCore.Relational/Query/RelationalLiftableConstantProcessor.cs
+++ b/src/EFCore.Relational/Query/RelationalLiftableConstantProcessor.cs
@@ -36,7 +36,7 @@ protected override ConstantExpression InlineConstant(LiftableConstantExpression
if (liftableConstant.ResolverExpression is Expression>
resolverExpression)
{
- var resolver = resolverExpression.Compile(preferInterpretation: true);
+ var resolver = resolverExpression.Compile(preferInterpretation: UseOldBehavior35208);
var value = resolver(_relationalMaterializerLiftableConstantContext);
return Expression.Constant(value, liftableConstant.Type);
}
diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs
index 60b910af18a..1f8da845072 100644
--- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs
@@ -24,6 +24,9 @@ public partial class RelationalShapedQueryCompilingExpressionVisitor
///
public sealed partial class ShaperProcessingExpressionVisitor : ExpressionVisitor
{
+ private static readonly bool UseOldBehavior35212 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue35212", out var enabled35212) && enabled35212;
+
///
/// Reading database values
///
@@ -858,16 +861,46 @@ when GetProjectionIndex(collectionResultExpression.ProjectionBindingExpression)
QueryCompilationContext.QueryContextParameter,
_dataReaderParameter);
+ var parentIdentifierExpression = UseOldBehavior35212
+ ? parentIdentifierLambda
+ : _parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
+ parentIdentifierLambda.Compile(),
+ Lambda>(
+ parentIdentifierLambda,
+ Parameter(typeof(MaterializerLiftableConstantContext), "_")),
+ "parentIdentifierLambda",
+ typeof(Func));
+
var outerIdentifierLambda = Lambda(
Visit(relationalCollectionShaperExpression.OuterIdentifier),
QueryCompilationContext.QueryContextParameter,
_dataReaderParameter);
+ var outerIdentifierExpression = UseOldBehavior35212
+ ? outerIdentifierLambda
+ : _parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
+ outerIdentifierLambda.Compile(),
+ Lambda>(
+ outerIdentifierLambda,
+ Parameter(typeof(MaterializerLiftableConstantContext), "_")),
+ "outerIdentifierLambda",
+ typeof(Func));
+
var selfIdentifierLambda = Lambda(
Visit(relationalCollectionShaperExpression.SelfIdentifier),
QueryCompilationContext.QueryContextParameter,
_dataReaderParameter);
+ var selfIdentifierExpression = UseOldBehavior35212
+ ? selfIdentifierLambda
+ : _parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
+ selfIdentifierLambda.Compile(),
+ Lambda>(
+ selfIdentifierLambda,
+ Parameter(typeof(MaterializerLiftableConstantContext), "_")),
+ "selfIdentifierLambda",
+ typeof(Func));
+
_inline = false;
_includeExpressions.Add(
@@ -878,8 +911,8 @@ when GetProjectionIndex(collectionResultExpression.ProjectionBindingExpression)
_dataReaderParameter,
_resultCoordinatorParameter,
entity,
- parentIdentifierLambda,
- outerIdentifierLambda,
+ parentIdentifierExpression,
+ outerIdentifierExpression,
_parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
navigation,
LiftableConstantExpressionHelpers.BuildNavigationAccessLambda(navigation),
@@ -907,9 +940,9 @@ when GetProjectionIndex(collectionResultExpression.ProjectionBindingExpression)
QueryCompilationContext.QueryContextParameter,
_dataReaderParameter,
_resultCoordinatorParameter,
- parentIdentifierLambda,
- outerIdentifierLambda,
- selfIdentifierLambda,
+ parentIdentifierExpression,
+ outerIdentifierExpression,
+ selfIdentifierExpression,
_parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
relationalCollectionShaperExpression.ParentIdentifierValueComparers
.Select(x => (Func