diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosProjectionBindingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosProjectionBindingExpressionVisitor.cs index c875cb00104..2bfbcce59d7 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosProjectionBindingExpressionVisitor.cs @@ -26,6 +26,10 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal /// public class CosmosProjectionBindingExpressionVisitor : ExpressionVisitor { + private static readonly MethodInfo _getParameterValueMethodInfo + = typeof(CosmosProjectionBindingExpressionVisitor) + .GetTypeInfo().GetDeclaredMethod(nameof(GetParameterValue)); + private readonly CosmosSqlTranslatingExpressionVisitor _sqlTranslator; private readonly IModel _model; private SelectExpression _selectExpression; @@ -83,6 +87,8 @@ public virtual Expression Translate([NotNull] SelectExpression selectExpression, _projectionMembers.Clear(); _projectionMapping.Clear(); + result = MatchTypes(result, expression.Type); + return result; } @@ -148,7 +154,7 @@ public override Expression Visit(Expression expression) } return new ProjectionBindingExpression( - _selectExpression, _selectExpression.AddToProjection(translation), expression.Type); + _selectExpression, _selectExpression.AddToProjection(translation), expression.Type.MakeNullable()); } else { @@ -160,17 +166,117 @@ public override Expression Visit(Expression expression) _projectionMapping[_projectionMembers.Peek()] = translation; - return new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type); + return new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type.MakeNullable()); } } - private static readonly MethodInfo _getParameterValueMethodInfo - = typeof(CosmosProjectionBindingExpressionVisitor) - .GetTypeInfo().GetDeclaredMethod(nameof(GetParameterValue)); + /// + /// 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. + /// + protected override Expression VisitBinary(BinaryExpression binaryExpression) + { + var left = MatchTypes(Visit(binaryExpression.Left), binaryExpression.Left.Type); + var right = MatchTypes(Visit(binaryExpression.Right), binaryExpression.Right.Type); - [UsedImplicitly] - private static T GetParameterValue(QueryContext queryContext, string parameterName) - => (T)queryContext.ParameterValues[parameterName]; + return binaryExpression.Update(left, VisitAndConvert(binaryExpression.Conversion, "VisitBinary"), right); + } + + /// + /// 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. + /// + protected override Expression VisitConditional(ConditionalExpression conditionalExpression) + { + var test = Visit(conditionalExpression.Test); + var ifTrue = Visit(conditionalExpression.IfTrue); + var ifFalse = Visit(conditionalExpression.IfFalse); + + if (test.Type == typeof(bool?)) + { + test = Expression.Equal(test, Expression.Constant(true, typeof(bool?))); + } + + return conditionalExpression.Update(test, ifTrue, ifFalse); + } + + /// + /// 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. + /// + protected override Expression VisitExtension(Expression extensionExpression) + { + Check.NotNull(extensionExpression, nameof(extensionExpression)); + + switch (extensionExpression) + { + case EntityShaperExpression entityShaperExpression: + { + var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression; + VerifySelectExpression(projectionBindingExpression); + + if (_clientEval) + { + var entityProjection = (EntityProjectionExpression)_selectExpression.GetMappedProjection( + projectionBindingExpression.ProjectionMember); + + return entityShaperExpression.Update( + new ProjectionBindingExpression( + _selectExpression, _selectExpression.AddToProjection(entityProjection), typeof(ValueBuffer))); + } + + _projectionMapping[_projectionMembers.Peek()] + = _selectExpression.GetMappedProjection(projectionBindingExpression.ProjectionMember); + + return entityShaperExpression.Update( + new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), typeof(ValueBuffer))); + } + + case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression: + return materializeCollectionNavigationExpression.Navigation is INavigation embeddableNavigation + && embeddableNavigation.IsEmbedded() + ? base.Visit(materializeCollectionNavigationExpression.Subquery) + : base.VisitExtension(materializeCollectionNavigationExpression); + + case IncludeExpression includeExpression: + if (!_clientEval) + { + return null; + } + + if (!(includeExpression.Navigation is INavigation includableNavigation + && includableNavigation.IsEmbedded())) + { + throw new InvalidOperationException(CosmosStrings.NonEmbeddedIncludeNotSupported(includeExpression.Print())); + } + + _includedNavigations.Push(includableNavigation); + + var newIncludeExpression = base.VisitExtension(includeExpression); + + _includedNavigations.Pop(); + + return newIncludeExpression; + + default: + throw new InvalidOperationException(CoreStrings.QueryFailed(extensionExpression.Print(), GetType().Name)); + } + } + + /// + /// 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. + /// + protected override ElementInit VisitElementInit(ElementInit elementInit) + => elementInit.Update(elementInit.Arguments.Select(e => MatchTypes(Visit(e), e.Type))); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -201,13 +307,13 @@ protected override Expression VisitMember(MemberExpression memberExpression) if (shaperExpression == null || unaryExpression.NodeType != ExpressionType.Convert) { - return memberExpression.Update(innerExpression); + return NullSafeUpdate(innerExpression); } break; default: - return memberExpression.Update(innerExpression); + return NullSafeUpdate(innerExpression); } EntityProjectionExpression innerEntityProjection; @@ -233,7 +339,7 @@ protected override Expression VisitMember(MemberExpression memberExpression) if (!(propertyBase is INavigation navigation) || !navigation.IsEmbedded()) { - return memberExpression.Update(innerExpression); + return NullSafeUpdate(innerExpression); } switch (navigationProjection) @@ -262,6 +368,96 @@ protected override Expression VisitMember(MemberExpression memberExpression) default: throw new InvalidOperationException(CoreStrings.QueryFailed(memberExpression.Print(), GetType().Name)); } + + Expression NullSafeUpdate(Expression expression) + { + Expression updatedMemberExpression = memberExpression.Update( + expression != null ? MatchTypes(expression, memberExpression.Expression.Type) : expression); + + if (expression?.Type.IsNullableType() == true) + { + var nullableReturnType = memberExpression.Type.MakeNullable(); + if (!memberExpression.Type.IsNullableType()) + { + updatedMemberExpression = Expression.Convert(updatedMemberExpression, nullableReturnType); + } + + updatedMemberExpression = Expression.Condition( + Expression.Equal(expression, Expression.Default(expression.Type)), + Expression.Constant(null, nullableReturnType), + updatedMemberExpression); + } + + return updatedMemberExpression; + } + } + + /// + /// 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. + /// + protected override MemberAssignment VisitMemberAssignment(MemberAssignment memberAssignment) + { + var expression = memberAssignment.Expression; + Expression visitedExpression; + if (_clientEval) + { + visitedExpression = Visit(memberAssignment.Expression); + } + else + { + var projectionMember = _projectionMembers.Peek().Append(memberAssignment.Member); + _projectionMembers.Push(projectionMember); + + visitedExpression = Visit(memberAssignment.Expression); + if (visitedExpression == null) + { + return null; + } + + _projectionMembers.Pop(); + } + + visitedExpression = MatchTypes(visitedExpression, expression.Type); + + return memberAssignment.Update(visitedExpression); + } + + /// + /// 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. + /// + protected override Expression VisitMemberInit(MemberInitExpression memberInitExpression) + { + Check.NotNull(memberInitExpression, nameof(memberInitExpression)); + + var newExpression = Visit(memberInitExpression.NewExpression); + if (newExpression == null) + { + return null; + } + + var newBindings = new MemberBinding[memberInitExpression.Bindings.Count]; + for (var i = 0; i < newBindings.Length; i++) + { + if (memberInitExpression.Bindings[i].BindingType != MemberBindingType.Assignment) + { + return null; + } + + newBindings[i] = VisitMemberBinding(memberInitExpression.Bindings[i]); + + if (newBindings[i] == null) + { + return null; + } + } + + return memberInitExpression.Update((NewExpression)newExpression, newBindings); } /// @@ -413,72 +609,34 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp } } - return base.VisitMethodCall(methodCallExpression); - } + var @object = Visit(methodCallExpression.Object); + var arguments = new Expression[methodCallExpression.Arguments.Count]; + for (var i = 0; i < methodCallExpression.Arguments.Count; i++) + { + var argument = methodCallExpression.Arguments[i]; + arguments[i] = MatchTypes(Visit(argument), argument.Type); + } - /// - /// 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. - /// - protected override Expression VisitExtension(Expression extensionExpression) - { - Check.NotNull(extensionExpression, nameof(extensionExpression)); + Expression updatedMethodCallExpression = methodCallExpression.Update( + @object != null ? MatchTypes(@object, methodCallExpression.Object.Type) : @object, + arguments); - switch (extensionExpression) + if (@object?.Type.IsNullableType() == true + && !methodCallExpression.Object.Type.IsNullableType()) { - case EntityShaperExpression entityShaperExpression: + var nullableReturnType = methodCallExpression.Type.MakeNullable(); + if (!methodCallExpression.Type.IsNullableType()) { - var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression; - VerifySelectExpression(projectionBindingExpression); - - if (_clientEval) - { - var entityProjection = (EntityProjectionExpression)_selectExpression.GetMappedProjection( - projectionBindingExpression.ProjectionMember); - - return entityShaperExpression.Update( - new ProjectionBindingExpression( - _selectExpression, _selectExpression.AddToProjection(entityProjection), typeof(ValueBuffer))); - } - - _projectionMapping[_projectionMembers.Peek()] - = _selectExpression.GetMappedProjection(projectionBindingExpression.ProjectionMember); - - return entityShaperExpression.Update( - new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), typeof(ValueBuffer))); + updatedMethodCallExpression = Expression.Convert(updatedMethodCallExpression, nullableReturnType); } - case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression: - return materializeCollectionNavigationExpression.Navigation is INavigation embeddableNavigation - && embeddableNavigation.IsEmbedded() - ? base.Visit(materializeCollectionNavigationExpression.Subquery) - : base.VisitExtension(materializeCollectionNavigationExpression); - - case IncludeExpression includeExpression: - if (!_clientEval) - { - return null; - } - - if (!(includeExpression.Navigation is INavigation includableNavigation - && includableNavigation.IsEmbedded())) - { - throw new InvalidOperationException(CosmosStrings.NonEmbeddedIncludeNotSupported(includeExpression.Print())); - } - - _includedNavigations.Push(includableNavigation); - - var newIncludeExpression = base.VisitExtension(includeExpression); - - _includedNavigations.Pop(); - - return newIncludeExpression; - - default: - throw new InvalidOperationException(CoreStrings.QueryFailed(extensionExpression.Print(), GetType().Name)); + return Expression.Condition( + Expression.Equal(@object, Expression.Default(@object.Type)), + Expression.Constant(null, nullableReturnType), + updatedMethodCallExpression); } + + return updatedMethodCallExpression; } /// @@ -505,22 +663,26 @@ protected override Expression VisitNew(NewExpression newExpression) var newArguments = new Expression[newExpression.Arguments.Count]; for (var i = 0; i < newArguments.Length; i++) { + var argument = newExpression.Arguments[i]; + Expression visitedArgument; if (_clientEval) { - newArguments[i] = Visit(newExpression.Arguments[i]); + visitedArgument = Visit(argument); } else { var projectionMember = _projectionMembers.Peek().Append(newExpression.Members[i]); _projectionMembers.Push(projectionMember); - newArguments[i] = Visit(newExpression.Arguments[i]); - if (newArguments[i] == null) + visitedArgument = Visit(argument); + if (visitedArgument == null) { return null; } _projectionMembers.Pop(); } + + newArguments[i] = MatchTypes(visitedArgument, argument.Type); } return newExpression.Update(newArguments); @@ -532,34 +694,8 @@ protected override Expression VisitNew(NewExpression newExpression) /// 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. /// - protected override Expression VisitMemberInit(MemberInitExpression memberInitExpression) - { - Check.NotNull(memberInitExpression, nameof(memberInitExpression)); - - var newExpression = Visit(memberInitExpression.NewExpression); - if (newExpression == null) - { - return null; - } - - var newBindings = new MemberBinding[memberInitExpression.Bindings.Count]; - for (var i = 0; i < newBindings.Length; i++) - { - if (memberInitExpression.Bindings[i].BindingType != MemberBindingType.Assignment) - { - return null; - } - - newBindings[i] = VisitMemberBinding(memberInitExpression.Bindings[i]); - - if (newBindings[i] == null) - { - return null; - } - } - - return memberInitExpression.Update((NewExpression)newExpression, newBindings); - } + protected override Expression VisitNewArray(NewArrayExpression newArrayExpression) + => newArrayExpression.Update(newArrayExpression.Expressions.Select(e => MatchTypes(Visit(e), e.Type))); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -567,24 +703,15 @@ protected override Expression VisitMemberInit(MemberInitExpression memberInitExp /// 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. /// - protected override MemberAssignment VisitMemberAssignment(MemberAssignment memberAssignment) + protected override Expression VisitUnary(UnaryExpression unaryExpression) { - if (_clientEval) - { - return memberAssignment.Update(Visit(memberAssignment.Expression)); - } + var operand = Visit(unaryExpression.Operand); - var projectionMember = _projectionMembers.Peek().Append(memberAssignment.Member); - _projectionMembers.Push(projectionMember); - - var visitedExpression = Visit(memberAssignment.Expression); - if (visitedExpression == null) - { - return null; - } - - _projectionMembers.Pop(); - return memberAssignment.Update(visitedExpression); + return (unaryExpression.NodeType == ExpressionType.Convert + || unaryExpression.NodeType == ExpressionType.ConvertChecked) + && unaryExpression.Type == operand.Type + ? operand + : unaryExpression.Update(MatchTypes(operand, unaryExpression.Operand.Type)); } // TODO: Debugging @@ -595,5 +722,22 @@ private void VerifySelectExpression(ProjectionBindingExpression projectionBindin throw new InvalidOperationException(CoreStrings.QueryFailed(projectionBindingExpression.Print(), GetType().Name)); } } + + private static Expression MatchTypes(Expression expression, Type targetType) + { + if (targetType != expression.Type + && targetType.TryGetSequenceType() == null) + { + Check.DebugAssert(targetType.MakeNullable() == expression.Type, "expression.Type must be nullable of targetType"); + + expression = Expression.Convert(expression, targetType); + } + + return expression; + } + + [UsedImplicitly] + private static T GetParameterValue(QueryContext queryContext, string parameterName) + => (T)queryContext.ParameterValues[parameterName]; } } diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs index 8955a05bb4e..c7b6445882e 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs @@ -385,7 +385,10 @@ protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression so selectExpression.ClearOrdering(); selectExpression.ReplaceProjectionMapping(projectionMapping); - return source.UpdateShaperExpression(new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int))); + return source.UpdateShaperExpression( + Expression.Convert( + new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int?)), + typeof(int))); } /// @@ -631,7 +634,10 @@ protected override ShapedQueryExpression TranslateLongCount(ShapedQueryExpressio selectExpression.ClearOrdering(); selectExpression.ReplaceProjectionMapping(projectionMapping); - return source.UpdateShaperExpression(new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(long))); + return source.UpdateShaperExpression( + Expression.Convert( + new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(long?)), + typeof(long))); } /// @@ -1132,8 +1138,7 @@ private ShapedQueryExpression AggregateResultShaper( selectExpression.ClearOrdering(); var nullableResultType = resultType.MakeNullable(); - Expression shaper = new ProjectionBindingExpression( - source.QueryExpression, new ProjectionMember(), throwOnNullResult ? nullableResultType : projection.Type); + Expression shaper = new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), nullableResultType); if (throwOnNullResult) { diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingExpressionVisitorBase.cs b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingExpressionVisitorBase.cs index 801d47c85d0..aac57f1d65f 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingExpressionVisitorBase.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingExpressionVisitorBase.cs @@ -640,7 +640,9 @@ private Expression CreateGetValueExpression( return Expression.Default(clrType); } - return CreateGetValueExpression(jObjectExpression, storeName, clrType, property.GetTypeMapping()); + return Expression.Convert( + CreateGetValueExpression(jObjectExpression, storeName, clrType.MakeNullable(), property.GetTypeMapping()), + clrType); } private Expression CreateGetValueExpression( @@ -649,6 +651,8 @@ private Expression CreateGetValueExpression( Type clrType, CoreTypeMapping typeMapping = null) { + Check.DebugAssert(clrType.IsNullableType(), "Must read nullable type from JObject."); + var innerExpression = jObjectExpression; if (_projectionBindings.TryGetValue(jObjectExpression, out var innerVariable)) { diff --git a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs index 20b4f886e8d..34c41454752 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs @@ -30,6 +30,7 @@ private static readonly MethodInfo _getParameterValueMethodInfo private readonly RelationalQueryableMethodTranslatingExpressionVisitor _queryableMethodTranslatingExpressionVisitor; private readonly RelationalSqlTranslatingExpressionVisitor _sqlTranslator; + private readonly IncludeFindingExpressionVisitor _includeFindingExpressionVisitor; private SelectExpression _selectExpression; private SqlExpression[] _existingProjections; @@ -52,6 +53,7 @@ public RelationalProjectionBindingExpressionVisitor( { _queryableMethodTranslatingExpressionVisitor = queryableMethodTranslatingExpressionVisitor; _sqlTranslator = sqlTranslatingExpressionVisitor; + _includeFindingExpressionVisitor = new IncludeFindingExpressionVisitor(); } /// @@ -367,7 +369,8 @@ protected override Expression VisitMember(MemberExpression memberExpression) Expression updatedMemberExpression = memberExpression.Update( expression != null ? MatchTypes(expression, memberExpression.Expression.Type) : expression); - if (expression?.Type.IsNullableValueType() == true) + if (expression?.Type.IsNullableType() == true + && !_includeFindingExpressionVisitor.ContainsInclude(expression)) { var nullableReturnType = memberExpression.Type.MakeNullable(); if (!memberExpression.Type.IsNullableType()) @@ -591,5 +594,33 @@ private static Expression MatchTypes(Expression expression, Type targetType) private static T GetParameterValue(QueryContext queryContext, string parameterName) #pragma warning restore IDE0052 // Remove unread private members => (T)queryContext.ParameterValues[parameterName]; + + private sealed class IncludeFindingExpressionVisitor : ExpressionVisitor + { + private bool _containsInclude; + + public bool ContainsInclude(Expression expression) + { + _containsInclude = false; + + Visit(expression); + + return _containsInclude; + } + + public override Expression Visit(Expression expression) => _containsInclude ? expression : base.Visit(expression); + + protected override Expression VisitExtension(Expression extensionExpression) + { + if (extensionExpression is IncludeExpression) + { + _containsInclude = true; + + return extensionExpression; + } + + return base.VisitExtension(extensionExpression); + } + } } } diff --git a/test/EFCore.Cosmos.FunctionalTests/BuiltInDataTypesCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/BuiltInDataTypesCosmosTest.cs index 7a1371feb4b..f685f4ac7de 100644 --- a/test/EFCore.Cosmos.FunctionalTests/BuiltInDataTypesCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/BuiltInDataTypesCosmosTest.cs @@ -80,12 +80,6 @@ FROM root c WHERE ((c[""Discriminator""] = ""BuiltInDataTypes"") AND (c[""Id""] = 13))"); } - [ConditionalFact(Skip = "Issue#21678")] - public override void Optional_datetime_reading_null_from_database() - { - base.Optional_datetime_reading_null_from_database(); - } - private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs index 70ca847e7db..76dae8422d4 100644 --- a/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs @@ -152,12 +152,6 @@ public override void Optional_owned_with_converter_reading_non_nullable_column() base.Optional_owned_with_converter_reading_non_nullable_column(); } - [ConditionalFact(Skip = "Issue#21678")] - public override void Optional_datetime_reading_null_from_database() - { - base.Optional_datetime_reading_null_from_database(); - } - private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs index 451f3d548c3..a85263ae58b 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs @@ -2308,12 +2308,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } + [ConditionalTheory(Skip = "Issue#13168")] public override Task Where_bitwise_or_with_logical_or(bool async) { - // #13168 - //await base.Where_bitwise_or_with_logical_or(async); - - return Task.CompletedTask; + return base.Where_bitwise_or_with_logical_or(async); } public override async Task Where_bitwise_and_with_logical_and(bool async) @@ -2326,12 +2324,10 @@ FROM root c WHERE ((c[""Discriminator""] = ""Customer"") AND (((c[""CustomerID""] = ""ALFKI"") & (c[""CustomerID""] = ""ANATR"")) AND (c[""CustomerID""] = ""ANTON"")))"); } + [ConditionalTheory(Skip = "Issue#13168")] public override Task Where_bitwise_or_with_logical_and(bool async) { - // #13168 - //await base.Where_bitwise_or_with_logical_and(async); - - return Task.CompletedTask; + return base.Where_bitwise_or_with_logical_and(async); } public override async Task Where_bitwise_and_with_logical_or(bool async) @@ -2409,12 +2405,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } + [ConditionalTheory(Skip = "Issue#13159")] public override Task Parameter_extraction_short_circuits_1(bool async) { - // #13159 - //await base.Parameter_extraction_short_circuits_1(async); - - return Task.CompletedTask; + return base.Parameter_extraction_short_circuits_1(async); } [ConditionalTheory(Skip = "Issue #17246")] @@ -2428,12 +2422,10 @@ FROM root c WHERE (c[""Discriminator""] = ""Order"")"); } + [ConditionalTheory(Skip = "Issue#13159")] public override Task Parameter_extraction_short_circuits_3(bool async) { - // #13159 - //await base.Parameter_extraction_short_circuits_3(async); - - return Task.CompletedTask; + return base.Parameter_extraction_short_circuits_3(async); } [ConditionalTheory(Skip = "Issue #17246")] @@ -4151,24 +4143,18 @@ public override Task Select_distinct_Select_with_client_bindings(bool async) return base.Select_distinct_Select_with_client_bindings(async); } - [ConditionalTheory(Skip = "Issue#21678")] - public override Task Non_nullable_property_through_optional_navigation(bool async) + [ConditionalTheory(Skip = "Non embedded collection subquery Issue#17246")] + public override Task Pending_selector_in_cardinality_reducing_method_is_applied_before_expanding_collection_navigation_member(bool async) { - return base.Non_nullable_property_through_optional_navigation(async); + return base.Pending_selector_in_cardinality_reducing_method_is_applied_before_expanding_collection_navigation_member(async); } - [ConditionalTheory(Skip = "Issue#21678")] + [ConditionalTheory(Skip = "Non embedded collection subquery Issue#17246")] public override Task Max_on_empty_sequence_throws(bool async) { return base.Max_on_empty_sequence_throws(async); } - [ConditionalTheory(Skip = "Non embedded collection subquery Issue#17246")] - public override Task Pending_selector_in_cardinality_reducing_method_is_applied_before_expanding_collection_navigation_member(bool async) - { - return base.Pending_selector_in_cardinality_reducing_method_is_applied_before_expanding_collection_navigation_member(async); - } - private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSetOperationsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSetOperationsQueryCosmosTest.cs deleted file mode 100644 index b8fa624db28..00000000000 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSetOperationsQueryCosmosTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Xunit.Abstractions; - -namespace Microsoft.EntityFrameworkCore.Query -{ - public class NorthwindSetOperationsQueryCosmosTest : NorthwindSetOperationsQueryTestBase> - { - public NorthwindSetOperationsQueryCosmosTest( - NorthwindQueryCosmosFixture fixture, - ITestOutputHelper testOutputHelper) - : base(fixture) - { - ClearLog(); - //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); - } - - // Set operations aren't supported on Cosmos - public override Task Concat(bool async) => Task.CompletedTask; - public override Task Concat_nested(bool async) => Task.CompletedTask; - public override Task Concat_non_entity(bool async) => Task.CompletedTask; - public override Task Except(bool async) => Task.CompletedTask; - public override Task Except_simple_followed_by_projecting_constant(bool async) => Task.CompletedTask; - public override Task Except_nested(bool async) => Task.CompletedTask; - public override Task Except_non_entity(bool async) => Task.CompletedTask; - public override Task Intersect(bool async) => Task.CompletedTask; - public override Task Intersect_nested(bool async) => Task.CompletedTask; - public override Task Intersect_non_entity(bool async) => Task.CompletedTask; - public override Task Union(bool async) => Task.CompletedTask; - public override Task Union_nested(bool async) => Task.CompletedTask; - public override Task Union_non_entity(bool async) => Task.CompletedTask; - public override Task Union_OrderBy_Skip_Take(bool async) => Task.CompletedTask; - public override Task Union_Where(bool async) => Task.CompletedTask; - public override Task Union_Skip_Take_OrderBy_ThenBy_Where(bool async) => Task.CompletedTask; - public override Task Union_Union(bool async) => Task.CompletedTask; - public override Task Union_Intersect(bool async) => Task.CompletedTask; - public override Task Union_Take_Union_Take(bool async) => Task.CompletedTask; - public override Task Select_Union(bool async) => Task.CompletedTask; - public override Task Union_Select(bool async) => Task.CompletedTask; - public override Task Union_Select_scalar(bool async) => Task.CompletedTask; - public override Task Union_with_anonymous_type_projection(bool async) => Task.CompletedTask; - public override Task Select_Union_unrelated(bool async) => Task.CompletedTask; - public override Task Select_Union_different_fields_in_anonymous_with_subquery(bool async) => Task.CompletedTask; - public override Task Union_Include(bool async) => Task.CompletedTask; - public override Task Include_Union(bool async) => Task.CompletedTask; - public override Task Select_Except_reference_projection(bool async) => Task.CompletedTask; - public override void Include_Union_only_on_one_side_throws() { } - public override void Include_Union_different_includes_throws() { } - public override Task SubSelect_Union(bool async) => Task.CompletedTask; - public override Task Client_eval_Union_FirstOrDefault(bool async) => Task.CompletedTask; - public override Task GroupBy_Select_Union(bool async) => Task.CompletedTask; - public override Task Union_over_columns_with_different_nullability(bool async) => Task.CompletedTask; - public override Task Union_over_different_projection_types(bool async, string leftType, string rightType) => Task.CompletedTask; - public override Task OrderBy_Take_Union(bool async) => Task.CompletedTask; - - private void AssertSql(params string[] expected) - => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); - - protected override void ClearLog() - => Fixture.TestSqlLoggerFactory.Clear(); - } -}