diff --git a/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs b/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs index f3e5c259847..cd46015679b 100644 --- a/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs +++ b/src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs @@ -131,6 +131,14 @@ public static string JsonPropertyCollision(object? property1, object? property2, public static string MissingOrderingInSelectExpression => GetString("MissingOrderingInSelectExpression"); + /// + /// Cosmos container '{container1}' is referenced by the query, but '{container2}' is already being referenced. A query can only reference a single Cosmos container. + /// + public static string MultipleContainersReferencedInQuery(object? container1, object? container2) + => string.Format( + GetString("MultipleContainersReferencedInQuery", nameof(container1), nameof(container2)), + container1, container2); + /// /// Navigation '{entityType}.{navigationName}' doesn't point to an embedded entity. /// diff --git a/src/EFCore.Cosmos/Properties/CosmosStrings.resx b/src/EFCore.Cosmos/Properties/CosmosStrings.resx index b432bfe31a1..2417a7c1a77 100644 --- a/src/EFCore.Cosmos/Properties/CosmosStrings.resx +++ b/src/EFCore.Cosmos/Properties/CosmosStrings.resx @@ -198,6 +198,9 @@ 'Reverse' could not be translated to the server because there is no ordering on the server side. + + Cosmos container '{container1}' is referenced by the query, but '{container2}' is already being referenced. A query can only reference a single Cosmos container. + Navigation '{entityType}.{navigationName}' doesn't point to an embedded entity. diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosQueryCompilationContext.cs b/src/EFCore.Cosmos/Query/Internal/CosmosQueryCompilationContext.cs index 49d99d3712d..1b0d35baf5d 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosQueryCompilationContext.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosQueryCompilationContext.cs @@ -12,6 +12,17 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal; public class CosmosQueryCompilationContext(QueryCompilationContextDependencies dependencies, bool async) : QueryCompilationContext(dependencies, async) { + /// + /// The name of the Cosmos container against which this query will be executed. + /// + /// + /// 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. + /// + public virtual string? CosmosContainer { get; internal set; } + /// /// 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.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs index 5b68e1c5798..73756688170 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs @@ -14,7 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal; /// public class CosmosQueryableMethodTranslatingExpressionVisitor : QueryableMethodTranslatingExpressionVisitor { - private readonly QueryCompilationContext _queryCompilationContext; + private readonly CosmosQueryCompilationContext _queryCompilationContext; private readonly ISqlExpressionFactory _sqlExpressionFactory; private readonly ITypeMappingSource _typeMappingSource; private readonly IMemberTranslatorProvider _memberTranslatorProvider; @@ -31,7 +31,7 @@ public class CosmosQueryableMethodTranslatingExpressionVisitor : QueryableMethod /// public CosmosQueryableMethodTranslatingExpressionVisitor( QueryableMethodTranslatingExpressionVisitorDependencies dependencies, - QueryCompilationContext queryCompilationContext, + CosmosQueryCompilationContext queryCompilationContext, ISqlExpressionFactory sqlExpressionFactory, ITypeMappingSource typeMappingSource, IMemberTranslatorProvider memberTranslatorProvider, @@ -258,13 +258,29 @@ protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVis protected override ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType) => CreateShapedQueryExpression(entityType, _sqlExpressionFactory.Select(entityType)); - private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType, Expression queryExpression) - => new( + private ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType, Expression queryExpression) + { + if (!entityType.IsOwned()) + { + var cosmosContainer = entityType.GetContainer(); + var existingContainer = _queryCompilationContext.CosmosContainer; + Check.DebugAssert(cosmosContainer is not null, "Non-owned entity type without a Cosmos container"); + + if (existingContainer is not null && existingContainer != cosmosContainer) + { + throw new InvalidOperationException(CosmosStrings.MultipleContainersReferencedInQuery(cosmosContainer, existingContainer)); + } + + _queryCompilationContext.CosmosContainer = cosmosContainer; + } + + return new ShapedQueryExpression( queryExpression, new StructuralTypeShaperExpression( entityType, new ProjectionBindingExpression(queryExpression, new ProjectionMember(), typeof(ValueBuffer)), false)); + } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -304,7 +320,7 @@ private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType ent } var translation = _sqlExpressionFactory.Exists(subquery); - var selectExpression = new SelectExpression(subquery.Container, translation); + var selectExpression = new SelectExpression(translation); return source.Update( selectExpression, @@ -368,18 +384,17 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou { // Simplify x.Array.Contains[1] => ARRAY_CONTAINS(x.Array, 1) insert of IN+subquery if (CosmosQueryUtils.TryExtractBareArray(source, out var array, ignoreOrderings: true) - && TranslateExpression(item) is SqlExpression translatedItem - && source.QueryExpression is SelectExpression { Container: var container }) + && TranslateExpression(item) is SqlExpression translatedItem) { if (array is ArrayConstantExpression arrayConstant) { var inExpression = _sqlExpressionFactory.In(translatedItem, arrayConstant.Items); - return source.Update(new SelectExpression(container, inExpression), source.ShaperExpression); + return source.Update(new SelectExpression(inExpression), source.ShaperExpression); } (translatedItem, array) = _sqlExpressionFactory.ApplyTypeMappingsOnItemAndArray(translatedItem, array); var simplifiedTranslation = _sqlExpressionFactory.Function("ARRAY_CONTAINS", new[] { array, translatedItem }, typeof(bool)); - return source.UpdateQueryExpression(new SelectExpression(container, simplifiedTranslation)); + return source.UpdateQueryExpression(new SelectExpression(simplifiedTranslation)); } // TODO: Translation to IN, with scalars and with subquery @@ -396,11 +411,10 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou { // Simplify x.Array.Count() => ARRAY_LENGTH(x.Array) instead of (SELECT COUNT(1) FROM i IN x.Array)) if (predicate is null - && CosmosQueryUtils.TryExtractBareArray(source, out var array, ignoreOrderings: true) - && source.QueryExpression is SelectExpression { Container: var container }) + && CosmosQueryUtils.TryExtractBareArray(source, out var array, ignoreOrderings: true)) { var simplifiedTranslation = _sqlExpressionFactory.Function("ARRAY_LENGTH", new[] { array }, typeof(int)); - return source.UpdateQueryExpression(new SelectExpression(container, simplifiedTranslation)); + return source.UpdateQueryExpression(new SelectExpression(simplifiedTranslation)); } var selectExpression = (SelectExpression)source.QueryExpression; @@ -470,12 +484,11 @@ protected override ShapedQueryExpression TranslateDistinct(ShapedQueryExpression // Simplify x.Array[1] => x.Array[1] (using the Cosmos array subscript operator) instead of a subquery with LIMIT/OFFSET if (!returnDefault && CosmosQueryUtils.TryExtractBareArray(source, out var array, out var projectedScalarReference) - && TranslateExpression(index) is { } translatedIndex - && source.QueryExpression is SelectExpression { Container: var container }) + && TranslateExpression(index) is { } translatedIndex) { var arrayIndex = _sqlExpressionFactory.ArrayIndex( array, translatedIndex, projectedScalarReference.Type, projectedScalarReference.TypeMapping); - return source.UpdateQueryExpression(new SelectExpression(container, arrayIndex)); + return source.UpdateQueryExpression(new SelectExpression(arrayIndex)); } // Note that Cosmos doesn't support OFFSET/LIMIT in subqueries, so this translation is for top-level entity querying only. @@ -1252,8 +1265,7 @@ when methodCallExpression.TryGetIndexerArguments(_queryCompilationContext.Model, var innerSelect = new SelectExpression( [new ProjectionExpression(inlineArray, null!)], sources: [], - orderings: [], - container: null!) + orderings: []) { UsesSingleValueProjection = true }; @@ -1289,8 +1301,7 @@ [new ProjectionExpression(inlineArray, null!)], var innerSelect = new SelectExpression( [new ProjectionExpression(sqlParameterExpression, null!)], sources: [], - orderings: [], - container: null!) + orderings: []) { UsesSingleValueProjection = true }; diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitorFactory.cs b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitorFactory.cs index f43f8fbe98b..b89f6d202ba 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitorFactory.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitorFactory.cs @@ -31,7 +31,7 @@ public class CosmosQueryableMethodTranslatingExpressionVisitorFactory( public virtual QueryableMethodTranslatingExpressionVisitor Create(QueryCompilationContext queryCompilationContext) => new CosmosQueryableMethodTranslatingExpressionVisitor( Dependencies, - queryCompilationContext, + (CosmosQueryCompilationContext)queryCompilationContext, sqlExpressionFactory, typeMappingSource, memberTranslatorProvider, diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable.cs b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable.cs index 8fcfe871c05..aa69ddf4524 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable.cs @@ -27,7 +27,8 @@ private sealed class QueryingEnumerable : IEnumerable, IAsyncEnumerable private readonly Func _shaper; private readonly IQuerySqlGeneratorFactory _querySqlGeneratorFactory; private readonly Type _contextType; - private readonly PartitionKey _partitionKeyValue; + private readonly string _cosmosContainer; + private readonly PartitionKey _cosmosPartitionKeyValue; private readonly IDiagnosticsLogger _queryLogger; private readonly bool _standAloneStateManager; private readonly bool _threadSafetyChecksEnabled; @@ -39,6 +40,7 @@ public QueryingEnumerable( SelectExpression selectExpression, Func shaper, Type contextType, + string cosmosContainer, PartitionKey partitionKeyValueFromExtension, bool standAloneStateManager, bool threadSafetyChecksEnabled) @@ -61,7 +63,8 @@ public QueryingEnumerable( throw new InvalidOperationException(CosmosStrings.PartitionKeyMismatch(partitionKeyValueFromExtension, partitionKey)); } - _partitionKeyValue = partitionKey != PartitionKey.None ? partitionKey : partitionKeyValueFromExtension; + _cosmosPartitionKeyValue = partitionKey != PartitionKey.None ? partitionKey : partitionKeyValueFromExtension; + _cosmosContainer = cosmosContainer; } public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) @@ -107,10 +110,10 @@ private sealed class Enumerator : IEnumerator { private readonly QueryingEnumerable _queryingEnumerable; private readonly CosmosQueryContext _cosmosQueryContext; - private readonly SelectExpression _selectExpression; private readonly Func _shaper; private readonly Type _contextType; - private readonly PartitionKey _partitionKeyValue; + private readonly string _cosmosContainer; + private readonly PartitionKey _cosmosPartitionKeyValue; private readonly IDiagnosticsLogger _queryLogger; private readonly bool _standAloneStateManager; private readonly IConcurrencyDetector _concurrencyDetector; @@ -123,9 +126,9 @@ public Enumerator(QueryingEnumerable queryingEnumerable) _queryingEnumerable = queryingEnumerable; _cosmosQueryContext = queryingEnumerable._cosmosQueryContext; _shaper = queryingEnumerable._shaper; - _selectExpression = queryingEnumerable._selectExpression; _contextType = queryingEnumerable._contextType; - _partitionKeyValue = queryingEnumerable._partitionKeyValue; + _cosmosContainer = queryingEnumerable._cosmosContainer; + _cosmosPartitionKeyValue = queryingEnumerable._cosmosPartitionKeyValue; _queryLogger = queryingEnumerable._queryLogger; _standAloneStateManager = queryingEnumerable._standAloneStateManager; _exceptionDetector = _cosmosQueryContext.ExceptionDetector; @@ -156,8 +159,8 @@ public bool MoveNext() _enumerator = _cosmosQueryContext.CosmosClient .ExecuteSqlQuery( - _selectExpression.Container, - _partitionKeyValue, + _cosmosContainer, + _cosmosPartitionKeyValue, sqlQuery) .GetEnumerator(); _cosmosQueryContext.InitializeStateManager(_standAloneStateManager); @@ -206,10 +209,10 @@ private sealed class AsyncEnumerator : IAsyncEnumerator { private readonly QueryingEnumerable _queryingEnumerable; private readonly CosmosQueryContext _cosmosQueryContext; - private readonly SelectExpression _selectExpression; private readonly Func _shaper; private readonly Type _contextType; - private readonly PartitionKey _partitionKeyValue; + private readonly string _cosmosContainer; + private readonly PartitionKey _cosmosPartitionKeyValue; private readonly IDiagnosticsLogger _queryLogger; private readonly bool _standAloneStateManager; private readonly CancellationToken _cancellationToken; @@ -223,9 +226,9 @@ public AsyncEnumerator(QueryingEnumerable queryingEnumerable, CancellationTok _queryingEnumerable = queryingEnumerable; _cosmosQueryContext = queryingEnumerable._cosmosQueryContext; _shaper = queryingEnumerable._shaper; - _selectExpression = queryingEnumerable._selectExpression; _contextType = queryingEnumerable._contextType; - _partitionKeyValue = queryingEnumerable._partitionKeyValue; + _cosmosContainer = queryingEnumerable._cosmosContainer; + _cosmosPartitionKeyValue = queryingEnumerable._cosmosPartitionKeyValue; _queryLogger = queryingEnumerable._queryLogger; _standAloneStateManager = queryingEnumerable._standAloneStateManager; _exceptionDetector = _cosmosQueryContext.ExceptionDetector; @@ -254,8 +257,8 @@ public async ValueTask MoveNextAsync() _enumerator = _cosmosQueryContext.CosmosClient .ExecuteSqlQueryAsync( - _selectExpression.Container, - _partitionKeyValue, + _cosmosContainer, + _cosmosPartitionKeyValue, sqlQuery) .GetAsyncEnumerator(_cancellationToken); _cosmosQueryContext.InitializeStateManager(_standAloneStateManager); diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.ReadItemQueryingEnumerable.cs b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.ReadItemQueryingEnumerable.cs index 948b67f22d4..420dc595df8 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.ReadItemQueryingEnumerable.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.ReadItemQueryingEnumerable.cs @@ -22,6 +22,7 @@ public partial class CosmosShapedQueryCompilingExpressionVisitor private sealed class ReadItemQueryingEnumerable : IEnumerable, IAsyncEnumerable, IQueryingEnumerable { private readonly CosmosQueryContext _cosmosQueryContext; + private readonly string _cosmosContainer; private readonly ReadItemExpression _readItemExpression; private readonly Func _shaper; private readonly Type _contextType; @@ -31,6 +32,7 @@ private sealed class ReadItemQueryingEnumerable : IEnumerable, IAsyncEnume public ReadItemQueryingEnumerable( CosmosQueryContext cosmosQueryContext, + string cosmosContainer, ReadItemExpression readItemExpression, Func shaper, Type contextType, @@ -38,6 +40,7 @@ public ReadItemQueryingEnumerable( bool threadSafetyChecksEnabled) { _cosmosQueryContext = cosmosQueryContext; + _cosmosContainer = cosmosContainer; _readItemExpression = readItemExpression; _shaper = shaper; _contextType = contextType; @@ -169,7 +172,7 @@ private bool TryGenerateIdFromKeys(IProperty idProperty, out object value) private sealed class Enumerator : IEnumerator, IAsyncEnumerator { private readonly CosmosQueryContext _cosmosQueryContext; - private readonly ReadItemExpression _readItemExpression; + private readonly string _cosmosContainer; private readonly Func _shaper; private readonly Type _contextType; private readonly IDiagnosticsLogger _queryLogger; @@ -185,7 +188,7 @@ private sealed class Enumerator : IEnumerator, IAsyncEnumerator public Enumerator(ReadItemQueryingEnumerable readItemEnumerable, CancellationToken cancellationToken = default) { _cosmosQueryContext = readItemEnumerable._cosmosQueryContext; - _readItemExpression = readItemEnumerable._readItemExpression; + _cosmosContainer = readItemEnumerable._cosmosContainer; _shaper = readItemEnumerable._shaper; _contextType = readItemEnumerable._contextType; _queryLogger = readItemEnumerable._queryLogger; @@ -227,7 +230,7 @@ public bool MoveNext() EntityFrameworkEventSource.Log.QueryExecuting(); _item = _cosmosQueryContext.CosmosClient.ExecuteReadItem( - _readItemExpression.Container, + _cosmosContainer, partitionKeyValue, resourceId); @@ -279,7 +282,7 @@ public async ValueTask MoveNextAsync() EntityFrameworkEventSource.Log.QueryExecuting(); _item = await _cosmosQueryContext.CosmosClient.ExecuteReadItemAsync( - _readItemExpression.Container, + _cosmosContainer, partitionKeyValue, resourceId, _cancellationToken) diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs index 3acf05dc059..93634431db9 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs @@ -35,6 +35,11 @@ public partial class CosmosShapedQueryCompilingExpressionVisitor( /// protected override Expression VisitShapedQuery(ShapedQueryExpression shapedQueryExpression) { + if (cosmosQueryCompilationContext.CosmosContainer is null) + { + throw new UnreachableException("No Cosmos container was set during query processing."); + } + var jObjectParameter = Parameter(typeof(JObject), "jObject"); var shaperBody = shapedQueryExpression.ShaperExpression; @@ -64,6 +69,7 @@ protected override Expression VisitShapedQuery(ShapedQueryExpression shapedQuery Constant(selectExpression), Constant(shaperLambda.Compile()), Constant(_contextType), + Constant(cosmosQueryCompilationContext.CosmosContainer), Constant(_partitionKeyValueFromExtension, typeof(PartitionKey)), Constant( QueryCompilationContext.QueryTrackingBehavior == QueryTrackingBehavior.NoTrackingWithIdentityResolution), @@ -85,6 +91,7 @@ protected override Expression VisitShapedQuery(ShapedQueryExpression shapedQuery Convert( QueryCompilationContext.QueryContextParameter, typeof(CosmosQueryContext)), + Constant(cosmosQueryCompilationContext.CosmosContainer), Constant(readItemExpression), Constant(shaperReadItemLambda.Compile()), Constant(_contextType), diff --git a/src/EFCore.Cosmos/Query/Internal/Expressions/ReadItemExpression.cs b/src/EFCore.Cosmos/Query/Internal/Expressions/ReadItemExpression.cs index 7b77dd70e89..1989781ce1f 100644 --- a/src/EFCore.Cosmos/Query/Internal/Expressions/ReadItemExpression.cs +++ b/src/EFCore.Cosmos/Query/Internal/Expressions/ReadItemExpression.cs @@ -32,14 +32,6 @@ public override Type Type public override ExpressionType NodeType => ExpressionType.Extension; - /// - /// 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. - /// - public virtual string Container { get; } - /// /// 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 @@ -74,9 +66,6 @@ public ReadItemExpression( IEntityType entityType, IDictionary propertyParameters) { - Container = entityType.GetContainer() - ?? throw new UnreachableException("No container ID, or trying to perform ReadItem on owned entity type"); - ProjectionExpression = new ProjectionExpression( new EntityProjectionExpression( entityType, diff --git a/src/EFCore.Cosmos/Query/Internal/Expressions/SelectExpression.cs b/src/EFCore.Cosmos/Query/Internal/Expressions/SelectExpression.cs index 1ab23bb3917..3f759ce9cc9 100644 --- a/src/EFCore.Cosmos/Query/Internal/Expressions/SelectExpression.cs +++ b/src/EFCore.Cosmos/Query/Internal/Expressions/SelectExpression.cs @@ -33,9 +33,6 @@ public class SelectExpression : Expression, IPrintableExpression /// public SelectExpression(IEntityType entityType) { - // TODO: All queries should reference a non-null container ID, but GetContainer returns null for owned entities. - Container = entityType.GetContainer()!; - // TODO: Redo aliasing _sources = [new SourceExpression(new ObjectReferenceExpression(entityType, "root"), RootAlias)]; _projectionMapping[new ProjectionMember()] @@ -50,8 +47,6 @@ _projectionMapping[new ProjectionMember()] /// public SelectExpression(IEntityType entityType, string sql, Expression argument) { - // TODO: All queries should reference a non-null container ID, but GetContainer returns null for owned entities. - Container = entityType.GetContainer()!; var fromSql = new FromSqlExpression(entityType.ClrType, sql, argument); _sources = [new SourceExpression(fromSql, RootAlias)]; _projectionMapping[new ProjectionMember()] = new EntityProjectionExpression( @@ -67,13 +62,11 @@ public SelectExpression(IEntityType entityType, string sql, Expression argument) public SelectExpression( List projections, List sources, - List orderings, - string container) + List orderings) { _projection = projections; _sources = sources; _orderings = orderings; - Container = container; } /// @@ -82,20 +75,11 @@ public SelectExpression( /// 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 SelectExpression(string container, SqlExpression projection) - : this(container) + public SelectExpression(SqlExpression projection) => _projectionMapping[new ProjectionMember()] = projection; - /// - /// 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. - /// - public SelectExpression(string? container) + private SelectExpression() { - // TODO: Move container out of SelectExpression to QueryCompilationContext - Container = container!; } /// @@ -108,7 +92,7 @@ public static SelectExpression CreateForPrimitiveCollection( SourceExpression source, Type elementClrType, CoreTypeMapping elementTypeMapping) - => new(container: null) + => new() { _sources = { source }, _projectionMapping = @@ -118,14 +102,6 @@ public static SelectExpression CreateForPrimitiveCollection( UsesSingleValueProjection = true }; - /// - /// 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. - /// - public virtual string Container { get; } - /// /// 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 @@ -568,7 +544,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) if (changed) { - var newSelectExpression = new SelectExpression(projections, sources, orderings, Container) + var newSelectExpression = new SelectExpression(projections, sources, orderings) { _projectionMapping = projectionMapping, Predicate = predicate, @@ -603,7 +579,7 @@ public virtual SelectExpression Update( projectionMapping[projectionMember] = expression; } - return new SelectExpression(projections, sources, orderings, Container) + return new SelectExpression(projections, sources, orderings) { _projectionMapping = projectionMapping, Predicate = predicate,