diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
index d0fb4fd1135..1ed5c6c8d0f 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
+++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
@@ -168,12 +168,12 @@ public static string ConflictingRowValuesSensitive(object? firstEntityType, obje
firstEntityType, secondEntityType, keyValue, firstConflictingValue, secondConflictingValue, column);
///
- /// Store type '{storeType1}' was inferred for a primitive collection, but that primitive collection was previously inferred to have store type '{storeType2}'.
+ /// Conflicting type mappings were inferred for column '{column}'.
///
- public static string ConflictingTypeMappingsForPrimitiveCollection(object? storeType1, object? storeType2)
+ public static string ConflictingTypeMappingsInferredForColumn(object? column)
=> string.Format(
- GetString("ConflictingTypeMappingsForPrimitiveCollection", nameof(storeType1), nameof(storeType2)),
- storeType1, storeType2);
+ GetString("ConflictingTypeMappingsInferredForColumn", nameof(column)),
+ column);
///
/// A seed entity for entity type '{entityType}' has the same key value as another seed entity mapped to the same table '{table}', but have different values for the column '{column}'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting values.
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx
index d6969185c9a..97b5fc2bc0d 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.resx
+++ b/src/EFCore.Relational/Properties/RelationalStrings.resx
@@ -175,8 +175,8 @@
Instances of entity types '{firstEntityType}' and '{secondEntityType}' are mapped to the same row with the key value '{keyValue}', but have different property values '{firstConflictingValue}' and '{secondConflictingValue}' for the column '{column}'.
-
- Store type '{storeType1}' was inferred for a primitive collection, but that primitive collection was previously inferred to have store type '{storeType2}'.
+
+ Conflicting type mappings were inferred for column '{column}'.
A seed entity for entity type '{entityType}' has the same key value as another seed entity mapped to the same table '{table}', but have different values for the column '{column}'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting values.
diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
index 04e8e1a6847..fec3abd6c8e 100644
--- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
@@ -491,6 +491,21 @@ private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType ent
///
protected override ShapedQueryExpression? TranslateContains(ShapedQueryExpression source, Expression item)
{
+ // Note that we don't apply the default type mapping to the item in order to allow it to be inferred from e.g. the subquery
+ // projection on the other side.
+ if (TranslateExpression(item, applyDefaultTypeMapping: false) is not SqlExpression translatedItem
+ || !TryGetProjection(source, out var projection))
+ {
+ // If the item can't be translated, we can't translate to an IN expression.
+ // However, attempt to translate as Any since that passes through Where predicate translation, which e.g. does entity equality.
+ var anyLambdaParameter = Expression.Parameter(item.Type, "p");
+ var anyLambda = Expression.Lambda(
+ Infrastructure.ExpressionExtensions.CreateEqualsExpression(anyLambdaParameter, item),
+ anyLambdaParameter);
+
+ return TranslateAny(source, anyLambda);
+ }
+
// Pattern-match Contains over ValuesExpression, translating to simplified 'item IN (1, 2, 3)' with constant elements
if (source.QueryExpression is SelectExpression
{
@@ -511,15 +526,9 @@ private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType ent
// Note that in the context of Contains we don't care about orderings
}
// Make sure that the source projects the column from the ValuesExpression directly, i.e. no projection out with some expression
- && TryGetProjection(source, out var projection)
&& projection is ColumnExpression projectedColumn
&& projectedColumn.Table == valuesExpression)
{
- if (TranslateExpression(item) is not SqlExpression translatedItem)
- {
- return null;
- }
-
var values = new object?[valuesExpression.RowValues.Count];
for (var i = 0; i < values.Length; i++)
{
@@ -543,13 +552,25 @@ private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType ent
}
}
- // TODO: This generates an EXISTS subquery. Translate to IN instead: #30955
- var anyLambdaParameter = Expression.Parameter(item.Type, "p");
- var anyLambda = Expression.Lambda(
- Infrastructure.ExpressionExtensions.CreateEqualsExpression(anyLambdaParameter, item),
- anyLambdaParameter);
+ // Translate to IN with a subquery.
+ // Note that because of null semantics, this may get transformed to an EXISTS subquery in SqlNullabilityProcessor.
+ var subquery = (SelectExpression)source.QueryExpression;
+ if (subquery.Limit == null
+ && subquery.Offset == null)
+ {
+ subquery.ClearOrdering();
+ }
+
+ subquery.ReplaceProjection(new List { projection });
+ subquery.ApplyProjection();
+
+ var translation = _sqlExpressionFactory.In(translatedItem, subquery, false);
+ subquery = _sqlExpressionFactory.Select(translation);
- return TranslateAny(source, anyLambda);
+ return source.Update(
+ subquery,
+ Expression.Convert(
+ new ProjectionBindingExpression(subquery, new ProjectionMember(), typeof(bool?)), typeof(bool)));
}
///
@@ -1771,10 +1792,13 @@ protected virtual bool IsValidSelectExpressionForExecuteUpdate(
/// Translates the given expression into equivalent SQL representation.
///
/// An expression to translate.
+ ///
+ /// Whether to apply the default type mapping on the top-most element if it has none. Defaults to .
+ ///
/// A which is translation of given expression or .
- protected virtual SqlExpression? TranslateExpression(Expression expression)
+ protected virtual SqlExpression? TranslateExpression(Expression expression, bool applyDefaultTypeMapping = true)
{
- var translation = _sqlTranslator.Translate(expression);
+ var translation = _sqlTranslator.Translate(expression, applyDefaultTypeMapping);
if (translation is null)
{
@@ -1809,7 +1833,7 @@ protected virtual bool IsValidSelectExpressionForExecuteUpdate(
///
protected virtual Expression ApplyInferredTypeMappings(
Expression expression,
- IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> inferredTypeMappings)
+ IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> inferredTypeMappings)
=> new RelationalInferredTypeMappingApplier(inferredTypeMappings).Visit(expression);
///
@@ -2541,12 +2565,12 @@ private bool TryGetProjection(ShapedQueryExpression shapedQueryExpression, [NotN
///
private sealed class ColumnTypeMappingScanner : ExpressionVisitor
{
- private readonly Dictionary<(TableExpressionBase, string), RelationalTypeMapping> _inferredColumns = new();
+ private readonly Dictionary<(TableExpressionBase, string), RelationalTypeMapping?> _inferredColumns = new();
private SelectExpression? _currentSelectExpression;
private ProjectionExpression? _currentProjectionExpression;
- public IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> Scan(Expression expression)
+ public IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> Scan(Expression expression)
{
_inferredColumns.Clear();
@@ -2583,6 +2607,19 @@ when WasMaybeOriginallyUntyped(columnExpression):
return base.VisitExtension(node);
}
+ // InExpression over a subquery: apply the item's type mapping on the subquery
+ case InExpression
+ {
+ Item.TypeMapping: { } typeMapping,
+ Subquery.Projection: [{ Expression: ColumnExpression columnExpression }]
+ }
+ when WasMaybeOriginallyUntyped(columnExpression):
+ {
+ RegisterInferredTypeMapping(columnExpression, typeMapping);
+
+ return base.VisitExtension(node);
+ }
+
// For set operations involving a leg with a type mapping (e.g. some column) and a leg without one (queryable constant or
// parameter), we infer the missing type mapping from the other side.
case SetOperationBase
@@ -2646,7 +2683,7 @@ when _currentSelectExpression is not null
return base.VisitExtension(node);
}
- bool WasMaybeOriginallyUntyped(ColumnExpression columnExpression)
+ static bool WasMaybeOriginallyUntyped(ColumnExpression columnExpression)
{
var underlyingTable = columnExpression.Table is JoinExpressionBase joinExpression
? joinExpression.Table
@@ -2654,9 +2691,15 @@ bool WasMaybeOriginallyUntyped(ColumnExpression columnExpression)
return underlyingTable switch
{
+ // TableExpressions are always fully-typed, with type mappings coming from the model
TableExpression
=> false,
+ // FromSqlExpressions always receive the default type mapping for the projected element type - we never need to infer
+ // them.
+ FromSqlExpression
+ => false,
+
SelectExpression subquery
=> subquery.Projection.FirstOrDefault(p => p.Alias == columnExpression.Name) is { Expression.TypeMapping: null },
@@ -2675,7 +2718,7 @@ SqlExpression UnwrapConvert(SqlExpression expression)
: expression;
}
- private void RegisterInferredTypeMapping(ColumnExpression columnExpression, RelationalTypeMapping inferredTypeMapping)
+ private void RegisterInferredTypeMapping(ColumnExpression columnExpression, RelationalTypeMapping? inferredTypeMapping)
{
var underlyingTable = columnExpression.Table is JoinExpressionBase joinExpression
? joinExpression.Table
@@ -2684,9 +2727,12 @@ private void RegisterInferredTypeMapping(ColumnExpression columnExpression, Rela
if (_inferredColumns.TryGetValue((underlyingTable, columnExpression.Name), out var knownTypeMapping)
&& inferredTypeMapping != knownTypeMapping)
{
- throw new InvalidOperationException(
- RelationalStrings.ConflictingTypeMappingsForPrimitiveCollection(
- inferredTypeMapping.StoreType, knownTypeMapping.StoreType));
+ // A different type mapping was already inferred for this column - we have a conflict.
+ // Null out the value for the inferred type mapping as an indication of the conflict. If it turns out that we need the
+ // inferred mapping later, during the application phase, we'll throw an exception at that point (not all the inferred type
+ // mappings here will actually be needed, so we don't want to needlessly throw here).
+ _inferredColumns[(underlyingTable, columnExpression.Name)] = null;
+ return;
}
_inferredColumns[(underlyingTable, columnExpression.Name)] = inferredTypeMapping;
@@ -2704,15 +2750,44 @@ protected class RelationalInferredTypeMappingApplier : ExpressionVisitor
///
/// The inferred type mappings to be applied back on their query roots.
///
- protected IReadOnlyDictionary<(TableExpressionBase Table, string ColumnName), RelationalTypeMapping> InferredTypeMappings { get; }
+ private IReadOnlyDictionary<(TableExpressionBase Table, string ColumnName), RelationalTypeMapping?> _inferredTypeMappings;
///
/// Creates a new instance of the class.
///
/// The inferred type mappings to be applied back on their query roots.
public RelationalInferredTypeMappingApplier(
- IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> inferredTypeMappings)
- => InferredTypeMappings = inferredTypeMappings;
+ IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> inferredTypeMappings)
+ => _inferredTypeMappings = inferredTypeMappings;
+
+ ///
+ /// Attempts to find an inferred type mapping for the given table column.
+ ///
+ /// The table containing the column for which to find the inferred type mapping.
+ /// The name of the column for which to find the inferred type mapping.
+ /// The inferred type mapping, or if none could be found.
+ /// Whether an inferred type mapping could be found.
+ protected virtual bool TryGetInferredTypeMapping(
+ TableExpressionBase table,
+ string columnName,
+ [NotNullWhen(true)] out RelationalTypeMapping? inferredTypeMapping)
+ {
+ if (_inferredTypeMappings.TryGetValue((table, columnName), out inferredTypeMapping))
+ {
+ // The inferred type mapping scanner records a null when two conflicting type mappings were inferred for the same
+ // column.
+ if (inferredTypeMapping is null)
+ {
+ throw new InvalidOperationException(
+ RelationalStrings.ConflictingTypeMappingsInferredForColumn(columnName));
+ }
+
+ return true;
+ }
+
+ inferredTypeMapping = null;
+ return false;
+ }
///
protected override Expression VisitExtension(Expression expression)
@@ -2720,7 +2795,7 @@ protected override Expression VisitExtension(Expression expression)
switch (expression)
{
case ColumnExpression { TypeMapping: null } columnExpression
- when InferredTypeMappings.TryGetValue((columnExpression.Table, columnExpression.Name), out var typeMapping):
+ when TryGetInferredTypeMapping(columnExpression.Table, columnExpression.Name, out var typeMapping):
return columnExpression.ApplyTypeMapping(typeMapping);
case SelectExpression selectExpression:
@@ -2762,7 +2837,7 @@ when InferredTypeMappings.TryGetValue((columnExpression.Table, columnExpression.
/// Whether to strip the _ord column.
protected virtual ValuesExpression ApplyTypeMappingsOnValuesExpression(ValuesExpression valuesExpression, bool stripOrdering)
{
- var inferredTypeMappings = InferredTypeMappings.TryGetValue((valuesExpression, ValuesValueColumnName), out var typeMapping)
+ var inferredTypeMappings = TryGetInferredTypeMapping(valuesExpression, ValuesValueColumnName, out var typeMapping)
? new[] { null, typeMapping }
: new RelationalTypeMapping?[] { null, null };
diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
index f0f490fc73f..3d50be65513 100644
--- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
@@ -118,33 +118,38 @@ protected virtual void AddTranslationErrorDetails(string details)
/// Translates an expression to an equivalent SQL representation.
///
/// An expression to translate.
+ ///
+ /// Whether to apply the default type mapping on the top-most element if it has none. Defaults to .
+ ///
/// A SQL translation of the given expression.
- public virtual SqlExpression? Translate(Expression expression)
+ public virtual SqlExpression? Translate(Expression expression, bool applyDefaultTypeMapping = true)
{
TranslationErrorDetails = null;
- return TranslateInternal(expression);
+ return TranslateInternal(expression, applyDefaultTypeMapping);
}
- private SqlExpression? TranslateInternal(Expression expression)
+ private SqlExpression? TranslateInternal(Expression expression, bool applyDefaultTypeMapping = true)
{
var result = Visit(expression);
if (result is SqlExpression translation)
{
- if (translation is SqlUnaryExpression sqlUnaryExpression
- && sqlUnaryExpression.OperatorType == ExpressionType.Convert
+ if (translation is SqlUnaryExpression { OperatorType: ExpressionType.Convert } sqlUnaryExpression
&& sqlUnaryExpression.Type == typeof(object))
{
translation = sqlUnaryExpression.Operand;
}
- translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation);
-
- if (translation.TypeMapping == null)
+ if (applyDefaultTypeMapping)
{
- // The return type is not-mappable hence return null
- return null;
+ translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation);
+
+ if (translation.TypeMapping == null)
+ {
+ // The return type is not-mappable hence return null
+ return null;
+ }
}
return translation;
diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
index 53d23cbdfdf..77898d2898f 100644
--- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs
+++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
@@ -600,9 +600,13 @@ public virtual InExpression In(SqlExpression item, SqlExpression values, bool ne
public virtual InExpression In(SqlExpression item, SelectExpression subquery, bool negated)
{
var sqlExpression = subquery.Projection.Single().Expression;
- var typeMapping = sqlExpression.TypeMapping;
+ var subqueryTypeMapping = sqlExpression.TypeMapping;
+
+ if (item.TypeMapping is null)
+ {
+ item = subqueryTypeMapping is null ? ApplyDefaultTypeMapping(item) : ApplyTypeMapping(item, subqueryTypeMapping);
+ }
- item = ApplyTypeMapping(item, typeMapping);
return new InExpression(item, subquery, negated, _boolTypeMapping);
}
diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
index bf39f8f5947..909d9daa921 100644
--- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
+++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
@@ -651,6 +651,9 @@ protected virtual SqlExpression VisitIn(InExpression inExpression, bool allowOpt
{
var item = Visit(inExpression.Item, out var itemNullable);
+ // If the InExpression is negated, it's as if we have an enclosing NOT, which prohibits optimized expansion.
+ allowOptimizedExpansion &= !inExpression.IsNegated;
+
if (inExpression.Subquery != null)
{
var subquery = Visit(inExpression.Subquery);
@@ -660,20 +663,121 @@ protected virtual SqlExpression VisitIn(InExpression inExpression, bool allowOpt
{
nullable = false;
- return subquery.Predicate!;
+ return _sqlExpressionFactory.Constant(inExpression.IsNegated, inExpression.TypeMapping);
+ }
+
+ // Check whether the subquery projects out a nullable value; note that we unwrap any casts to get to the underlying
+ // ColumnExpression (since casts don't affect nullability).
+ // Note: we could broaden the optimization if we knew the nullability of the projection but we don't keep that information and
+ // we want to avoid double visitation
+ var subqueryProjection = subquery.Projection.Single().Expression;
+
+ inExpression = inExpression.Update(item, values: null, subquery);
+
+ var unwrappedSubqueryProjection = subqueryProjection;
+ while (unwrappedSubqueryProjection is SqlUnaryExpression
+ {
+ OperatorType: ExpressionType.Convert or ExpressionType.ConvertChecked, Operand: var operand
+ })
+ {
+ unwrappedSubqueryProjection = operand;
+ }
+
+ var projectionNullable =
+ unwrappedSubqueryProjection is not ColumnExpression { IsNullable: false } and not SqlConstantExpression { Value: null };
+
+ if (UseRelationalNulls)
+ {
+ nullable = itemNullable || projectionNullable;
+
+ return inExpression;
}
- // if item is not nullable, and subquery contains a non-nullable column we know the result can never be null
- // note: in this case we could broaden the optimization if we knew the nullability of the projection
- // but we don't keep that information and we want to avoid double visitation
- nullable = !(!itemNullable
- && subquery.Projection.Count == 1
- && subquery.Projection[0].Expression is ColumnExpression columnProjection
- && !columnProjection.IsNullable);
+ nullable = false;
+
+ // SQL IN returns null when the item is null, and when the values (subquery projection) contains NULL and no match was made.
+
+ switch ((itemNullable, projectionNullable))
+ {
+ // If both sides are non-nullable, IN never returns null, so is safe to use as-is.
+ case (false, false):
+ return inExpression;
+
+ case (true, false):
+ {
+ // If the item is actually null (not just nullable) and the projection is non-nullable, just return false immediately:
+ // WHERE NULL IN (SELECT NonNullable FROM foo) -> false
+ if (IsNull(item))
+ {
+ return _sqlExpressionFactory.Constant(false, inExpression.TypeMapping);
+ }
+
+ // Otherwise, since the projection is non-nullable, NULL will only be returned if the item wasn't found. Use as-is
+ // in optimized expansion (NULL is interpreted as false anyway), or compensate for the item being possibly null:
+ // WHERE Nullable IN (SELECT NonNullable FROM foo) -> WHERE Nullable IN (SELECT NonNullable FROM foo) AND Nullable IS NOT NULL
+ // WHERE Nullable NOT IN (SELECT NonNullable FROM foo) -> WHERE Nullable NOT IN (SELECT NonNullable FROM foo) OR Nullable IS NULL
+ return allowOptimizedExpansion
+ ? inExpression
+ : inExpression.IsNegated
+ ? _sqlExpressionFactory.OrElse(inExpression, _sqlExpressionFactory.IsNull(item))
+ : _sqlExpressionFactory.AndAlso(inExpression, _sqlExpressionFactory.IsNotNull(item));
+ }
+
+ case (false, true):
+ {
+ // If the item is non-nullable but the projection is nullable, NULL will only be returned if the item wasn't found
+ // (as with the above case).
+ // Use as-is in optimized expansion (NULL is interpreted as false anyway), or compensate by coalescing NULL to false:
+ // WHERE NonNullable IN (SELECT Nullable FROM foo) -> WHERE COALESCE(NonNullable IN (SELECT Nullable FROM foo), false)
+ if (allowOptimizedExpansion)
+ {
+ return inExpression;
+ }
+
+ // On SQL Server, EXISTS isn't less efficient than IN, and the additional COALESCE (and CASE/WHEN which it requires)
+ // add unneeded clutter (and possibly hurt perf). So allow providers to prefer EXISTS.
+ if (PreferExistsToComplexIn)
+ {
+ goto TransformToExists;
+ }
+
+ return inExpression.IsNegated
+ ? _sqlExpressionFactory.Not(
+ _sqlExpressionFactory.Coalesce(inExpression.Negate(), _sqlExpressionFactory.Constant(false)))
+ : _sqlExpressionFactory.Coalesce(inExpression, _sqlExpressionFactory.Constant(false));
+ }
- return inExpression.Update(item, values: null, subquery);
+ case (true, true):
+ TransformToExists:
+ // Worst case: both sides are nullable; there's no way to distinguish the item was found or not.
+ // We rewrite to an EXISTS subquery where we can generate a precise predicate to check for what we need. Note that this
+ // performs (significantly) worse than an IN expression, since it involves a correlated subquery.
+
+ // We'll need to mutate the subquery to introduce the predicate inside it, but it might be referenced by other places in
+ // the tree, so we create a copy to work on.
+
+ // No need for a projection with EXISTS, clear it to get SELECT 1
+ subquery = subquery.Update(
+ Array.Empty(),
+ subquery.Tables,
+ subquery.Predicate,
+ subquery.GroupBy,
+ subquery.Having,
+ subquery.Orderings,
+ subquery.Limit,
+ subquery.Offset);
+
+ var predicate = VisitSqlBinary(
+ _sqlExpressionFactory.Equal(subqueryProjection, item), allowOptimizedExpansion: true, out _);
+ subquery.ApplyPredicate(predicate);
+ subquery.ClearOrdering();
+
+ return _sqlExpressionFactory.Exists(subquery, inExpression.IsNegated);
+ }
}
+ // Non-subquery case
+
// for relational null semantics we don't need to extract null values from the array
if (UseRelationalNulls
|| !(inExpression.Values is SqlConstantExpression || inExpression.Values is SqlParameterExpression))
@@ -1243,11 +1347,14 @@ protected virtual SqlExpression VisitJsonScalar(
return jsonScalarExpression;
}
+ ///
+ /// Determines whether an will be transformed to an when it would
+ /// otherwise require complex compensation for null semantics.
+ ///
+ protected virtual bool PreferExistsToComplexIn => false;
+
private static bool? TryGetBoolConstantValue(SqlExpression? expression)
- => expression is SqlConstantExpression constantExpression
- && constantExpression.Value is bool boolValue
- ? boolValue
- : null;
+ => expression is SqlConstantExpression { Value: bool boolValue } ? boolValue : null;
private void RestoreNonNullableColumnsList(int counter)
{
@@ -1930,6 +2037,10 @@ private static bool IsLogicalNot(SqlUnaryExpression? sqlUnaryExpression)
&& sqlUnaryExpression.OperatorType == ExpressionType.Not
&& sqlUnaryExpression.Type == typeof(bool);
+ private bool IsNull(SqlExpression expression)
+ => expression is SqlConstantExpression { Value: null }
+ || expression is SqlParameterExpression { Name: string parameterName } && ParameterValues[parameterName] is null;
+
// ?a == ?b -> [(a == b) && (a != null && b != null)] || (a == null && b == null))
//
// a | b | F1 = a == b | F2 = (a != null && b != null) | F3 = F1 && F2 |
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
index 73f5377c7c7..49b119e9a12 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
@@ -132,10 +132,11 @@ protected override ShapedQueryExpression TranslateCollection(
// apply a conversion from the values coming out of OPENJSON (always NVARCHAR(MAX)) to the required relational store type.
var openJsonExpression = new TableValuedFunctionExpression(tableAlias, "OPENJSON", new[] { sqlExpression });
- // TODO: When we have metadata to determine if the element is nullable, pass that here to SelectExpression
+ // TODO: This is a temporary CLR type-based check; when we have proper metadata to determine if the element is nullable, use it here
+ var isColumnNullable = elementClrType.IsNullableType();
+
var selectExpression = new SelectExpression(
- openJsonExpression, columnName: "value", columnType: elementClrType, columnTypeMapping: elementTypeMapping,
- isColumnNullable: null);
+ openJsonExpression, columnName: "value", columnType: elementClrType, columnTypeMapping: elementTypeMapping, isColumnNullable);
if (elementTypeMapping is { StoreType: not "nvarchar(max)" })
{
@@ -155,9 +156,7 @@ protected override ShapedQueryExpression TranslateCollection(
"value",
typeof(string),
_typeMappingSource.FindMapping("nvarchar(max)"),
- // TODO: When we have metadata to determine if the element is nullable, pass that here to
- // SelectExpression
- columnNullable: null),
+ isColumnNullable),
elementClrType,
elementTypeMapping)
}
@@ -402,7 +401,7 @@ public TemporalAnnotationApplyingExpressionVisitor(Func
protected override Expression ApplyInferredTypeMappings(
Expression expression,
- IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> inferredTypeMappings)
+ IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> inferredTypeMappings)
=> new SqlServerInferredTypeMappingApplier(_typeMappingSource, _sqlExpressionFactory, inferredTypeMappings).Visit(expression);
///
@@ -426,7 +425,7 @@ protected class SqlServerInferredTypeMappingApplier : RelationalInferredTypeMapp
public SqlServerInferredTypeMappingApplier(
IRelationalTypeMappingSource typeMappingSource,
ISqlExpressionFactory sqlExpressionFactory,
- IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> inferredTypeMappings)
+ IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> inferredTypeMappings)
: base(inferredTypeMappings)
=> (_typeMappingSource, _sqlExpressionFactory) = (typeMappingSource, sqlExpressionFactory);
@@ -441,7 +440,7 @@ protected override Expression VisitExtension(Expression expression)
switch (expression)
{
case TableValuedFunctionExpression { Name: "OPENJSON", Schema: null, IsBuiltIn: true } openJsonExpression
- when InferredTypeMappings.TryGetValue((openJsonExpression, "value"), out var typeMapping):
+ when TryGetInferredTypeMapping(openJsonExpression, "value", out var typeMapping):
return ApplyTypeMappingsOnOpenJsonExpression(openJsonExpression, new[] { typeMapping });
// Above, we applied the type mapping the the parameter that OPENJSON accepts as an argument.
@@ -455,7 +454,7 @@ when InferredTypeMappings.TryGetValue((openJsonExpression, "value"), out var typ
foreach (var table in selectExpression.Tables)
{
if (table is TableValuedFunctionExpression { Name: "OPENJSON", Schema: null, IsBuiltIn: true } openJsonExpression
- && InferredTypeMappings.TryGetValue((openJsonExpression, "value"), out var inferredTypeMapping))
+ && TryGetInferredTypeMapping(openJsonExpression, "value", out var inferredTypeMapping))
{
if (previousSelectInferredTypeMappings is null)
{
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs
index 581d699f869..1ed6b70820a 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs
@@ -104,4 +104,12 @@ protected virtual SqlExpression VisitSqlServerAggregateFunction(
orderings ?? aggregateFunctionExpression.Orderings)
: aggregateFunctionExpression;
}
+
+ ///
+ /// 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 bool PreferExistsToComplexIn => true;
}
diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs
index ccd80eb9f4a..6cdd83945e6 100644
--- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs
@@ -167,10 +167,11 @@ protected override ShapedQueryExpression TranslateCollection(
var jsonEachExpression = new TableValuedFunctionExpression(tableAlias, "json_each", new[] { sqlExpression });
- // TODO: When we have metadata to determine if the element is nullable, pass that here to SelectExpression
+ // TODO: This is a temporary CLR type-based check; when we have proper metadata to determine if the element is nullable, use it here
+ var isColumnNullable = elementClrType.IsNullableType();
+
var selectExpression = new SelectExpression(
- jsonEachExpression, columnName: "value", columnType: elementClrType, columnTypeMapping: elementTypeMapping,
- isColumnNullable: null);
+ jsonEachExpression, columnName: "value", columnType: elementClrType, columnTypeMapping: elementTypeMapping, isColumnNullable);
// TODO: SQLite does have REAL and BLOB types, which JSON does not. Need to possibly cast to that.
if (elementTypeMapping is not null)
@@ -187,7 +188,7 @@ protected override ShapedQueryExpression TranslateCollection(
"key",
typeof(int),
typeMapping: _typeMappingSource.FindMapping(typeof(int)),
- columnNullable: false),
+ isColumnNullable),
ascending: true));
Expression shaperExpression = new ProjectionBindingExpression(
@@ -284,7 +285,7 @@ private static Type GetProviderType(SqlExpression expression)
///
protected override Expression ApplyInferredTypeMappings(
Expression expression,
- IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> inferredTypeMappings)
+ IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> inferredTypeMappings)
=> new SqliteInferredTypeMappingApplier(_typeMappingSource, _sqlExpressionFactory, inferredTypeMappings).Visit(expression);
///
@@ -308,7 +309,7 @@ protected class SqliteInferredTypeMappingApplier : RelationalInferredTypeMapping
public SqliteInferredTypeMappingApplier(
IRelationalTypeMappingSource typeMappingSource,
ISqlExpressionFactory sqlExpressionFactory,
- IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping> inferredTypeMappings)
+ IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping?> inferredTypeMappings)
: base(inferredTypeMappings)
=> (_typeMappingSource, _sqlExpressionFactory) = (typeMappingSource, sqlExpressionFactory);
@@ -323,7 +324,7 @@ protected override Expression VisitExtension(Expression expression)
switch (expression)
{
case TableValuedFunctionExpression { Name: "json_each", Schema: null, IsBuiltIn: true } jsonEachExpression
- when InferredTypeMappings.TryGetValue((jsonEachExpression, "value"), out var typeMapping):
+ when TryGetInferredTypeMapping(jsonEachExpression, "value", out var typeMapping):
return ApplyTypeMappingsOnJsonEachExpression(jsonEachExpression, typeMapping);
// Above, we applied the type mapping the the parameter that json_each accepts as an argument.
@@ -337,7 +338,7 @@ when InferredTypeMappings.TryGetValue((jsonEachExpression, "value"), out var typ
foreach (var table in selectExpression.Tables)
{
if (table is TableValuedFunctionExpression { Name: "json_each", Schema: null, IsBuiltIn: true } jsonEachExpression
- && InferredTypeMappings.TryGetValue((jsonEachExpression, "value"), out var inferredTypeMapping))
+ && TryGetInferredTypeMapping(jsonEachExpression, "value", out var inferredTypeMapping))
{
if (previousSelectInferredTypeMappings is null)
{
diff --git a/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs
index eae0210accf..7bc1bc61ddd 100644
--- a/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/CustomConvertersCosmosTest.cs
@@ -133,6 +133,9 @@ public override void GroupBy_converted_enum()
Assert.Throws(() => base.GroupBy_converted_enum()).Message);
}
+ public override void Infer_type_mapping_from_in_subquery_to_item()
+ => Assert.Throws(() => base.Infer_type_mapping_from_in_subquery_to_item());
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
diff --git a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs
index d3e7c2b59ad..6b698250e53 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs
@@ -1154,7 +1154,75 @@ await AssertQueryScalar(
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
- public virtual async Task Null_semantics_contains_non_nullable_argument(bool async)
+ public virtual async Task Null_semantics_contains_non_nullable_item_with_non_nullable_subquery(bool async)
+ {
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => ss.Set().Select(e => e.StringA).Contains(e.StringA))
+ .Select(e => e.Id));
+
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => !ss.Set().Select(e => e.StringA).Contains(e.StringA))
+ .Select(e => e.Id));
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual async Task Null_semantics_contains_nullable_item_with_non_nullable_subquery(bool async)
+ {
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => ss.Set().Select(e => e.StringA).Contains(e.NullableStringA))
+ .Select(e => e.Id));
+
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => !ss.Set().Select(e => e.StringA).Contains(e.NullableStringA))
+ .Select(e => e.Id));
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual async Task Null_semantics_contains_non_nullable_item_with_nullable_subquery(bool async)
+ {
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => ss.Set().Select(e => e.NullableStringA).Contains(e.StringA))
+ .Select(e => e.Id));
+
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => !ss.Set().Select(e => e.NullableStringA).Contains(e.StringA))
+ .Select(e => e.Id));
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual async Task Null_semantics_contains_nullable_item_with_nullable_subquery(bool async)
+ {
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => ss.Set().Select(e => e.NullableStringA).Contains(e.NullableStringA))
+ .Select(e => e.Id));
+
+ await AssertQueryScalar(
+ async,
+ ss => ss.Set()
+ .Where(e => !ss.Set().Select(e => e.NullableStringA).Contains(e.NullableStringA))
+ .Select(e => e.Id));
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual async Task Null_semantics_contains_non_nullable_item_with_values(bool async)
{
var ids = new List
{
diff --git a/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs b/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
index c49fce96e5e..b31f6d30ac0 100644
--- a/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
+++ b/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
@@ -841,6 +841,16 @@ public enum SomeEnum
No
}
+ [ConditionalFact]
+ public virtual void Infer_type_mapping_from_in_subquery_to_item()
+ {
+ using var context = CreateContext();
+ var results = context.Set().Where(b =>
+ context.Set().Select(bb => bb.TestBoolean).Contains(true) && b.Id == 13).ToList();
+
+ Assert.Equal(1, results.Count);
+ }
+
public abstract class CustomConvertersFixtureBase : BuiltInDataTypesFixtureBase
{
protected override string StoreName
diff --git a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs
index 5b941c53520..24db1694251 100644
--- a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs
@@ -168,19 +168,19 @@ public virtual Task Parameter_collection_of_ints_Contains(bool async)
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
- public virtual Task Parameter_collection_of_nullable_ints_Contains(bool async)
+ public virtual Task Parameter_collection_of_nullable_ints_Contains_int(bool async)
{
var nullableInts = new int?[] { 10, 999 };
return AssertQuery(
async,
- ss => ss.Set().Where(c => nullableInts.Contains(c.NullableInt)),
+ ss => ss.Set().Where(c => nullableInts.Contains(c.Int)),
entryCount: 1);
}
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
- public virtual Task Parameter_collection_of_nullable_ints_Contains_null(bool async)
+ public virtual Task Parameter_collection_of_nullable_ints_Contains_nullable_int(bool async)
{
var nullableInts = new int?[] { null, 999 };
@@ -278,6 +278,14 @@ public virtual Task Column_collection_of_nullable_ints_Contains_null(bool async)
ss => ss.Set().Where(c => c.NullableInts.Contains(null)),
entryCount: 1);
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Column_collection_of_strings_contains_null(bool async)
+ => AssertQuery(
+ async,
+ ss => ss.Set().Where(c => c.Strings.Contains(null)),
+ entryCount: 0);
+
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Column_collection_of_bools_Contains(bool async)
diff --git a/test/EFCore.SqlServer.FunctionalTests/CustomConvertersSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/CustomConvertersSqlServerTest.cs
index 4f830041610..8b15e630f00 100644
--- a/test/EFCore.SqlServer.FunctionalTests/CustomConvertersSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/CustomConvertersSqlServerTest.cs
@@ -346,6 +346,21 @@ SELECT [HoldingEnum] FROM [HolderClass]
""");
}
+ public override void Infer_type_mapping_from_in_subquery_to_item()
+ {
+ base.Infer_type_mapping_from_in_subquery_to_item();
+
+ AssertSql(
+"""
+SELECT [b].[Id], [b].[Enum16], [b].[Enum32], [b].[Enum64], [b].[Enum8], [b].[EnumS8], [b].[EnumU16], [b].[EnumU32], [b].[EnumU64], [b].[PartitionId], [b].[TestBoolean], [b].[TestByte], [b].[TestCharacter], [b].[TestDateOnly], [b].[TestDateTime], [b].[TestDateTimeOffset], [b].[TestDecimal], [b].[TestDouble], [b].[TestInt16], [b].[TestInt32], [b].[TestInt64], [b].[TestSignedByte], [b].[TestSingle], [b].[TestTimeOnly], [b].[TestTimeSpan], [b].[TestUnsignedInt16], [b].[TestUnsignedInt32], [b].[TestUnsignedInt64]
+FROM [BuiltInDataTypes] AS [b]
+WHERE N'Yeps' IN (
+ SELECT [b0].[TestBoolean]
+ FROM [BuiltInDataTypes] AS [b0]
+) AND [b].[Id] = 13
+""");
+ }
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs
index 3b776e520e0..7b5cfba9801 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs
@@ -1993,14 +1993,14 @@ public override async Task Contains_with_subquery_optional_navigation_and_consta
SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id]
FROM [LevelOne] AS [l]
LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id]
-WHERE EXISTS (
- SELECT 1
+WHERE 1 IN (
+ SELECT [t].[Id]
FROM (
SELECT DISTINCT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id]
FROM [LevelThree] AS [l1]
WHERE [l0].[Id] IS NOT NULL AND [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]
) AS [t]
- WHERE [t].[Id] = 1)
+)
""");
}
@@ -2013,10 +2013,11 @@ public override async Task Contains_with_subquery_optional_navigation_scalar_dis
SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id]
FROM [LevelOne] AS [l]
LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id]
-WHERE EXISTS (
- SELECT DISTINCT 1
+WHERE 1 IN (
+ SELECT DISTINCT CAST(LEN([l1].[Name]) AS int)
FROM [LevelThree] AS [l1]
- WHERE [l0].[Id] IS NOT NULL AND [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id] AND CAST(LEN([l1].[Name]) AS int) = 1)
+ WHERE [l0].[Id] IS NOT NULL AND [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]
+)
""");
}
@@ -4046,10 +4047,11 @@ FROM [LevelOne] AS [l]
OUTER APPLY (
SELECT [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id]
FROM [LevelThree] AS [l0]
- WHERE EXISTS (
- SELECT 1
+ WHERE [l0].[Level2_Required_Id] IN (
+ SELECT [l1].[Id]
FROM [LevelTwo] AS [l1]
- WHERE [l].[Id] = [l1].[OneToMany_Required_Inverse2Id] AND [l1].[Id] = [l0].[Level2_Required_Id])
+ WHERE [l].[Id] = [l1].[OneToMany_Required_Inverse2Id]
+ )
) AS [t]
LEFT JOIN [LevelTwo] AS [l2] ON [l].[Id] = [l2].[OneToMany_Required_Inverse2Id]
ORDER BY [l].[Id], [t].[Id]
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs
index 9d01362a8e4..bfed06a4f5b 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs
@@ -571,7 +571,11 @@ WHEN [t0].[Level2_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse3
WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [t0].[Level2_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse3Id] IS NOT NULL AND EXISTS (
SELECT 1
FROM [Level1] AS [l3]
- WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l].[Id] = [l3].[OneToMany_Required_Inverse2Id] AND [l3].[Id] = [t0].[Level2_Required_Id])
+ WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l].[Id] = [l3].[OneToMany_Required_Inverse2Id] AND (CASE
+ WHEN [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l3].[Id]
+ END = [t0].[Level2_Required_Id] OR (CASE
+ WHEN [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l3].[Id]
+ END IS NULL AND [t0].[Level2_Required_Id] IS NULL)))
) AS [t1]
LEFT JOIN (
SELECT [l4].[Id], [l4].[OneToOne_Required_PK_Date], [l4].[Level1_Optional_Id], [l4].[Level1_Required_Id], [l4].[Level2_Name], [l4].[OneToMany_Optional_Inverse2Id], [l4].[OneToMany_Required_Inverse2Id], [l4].[OneToOne_Optional_PK_Inverse2Id]
@@ -1856,8 +1860,10 @@ LEFT JOIN (
FROM [Level1] AS [l0]
WHERE [l0].[OneToOne_Required_PK_Date] IS NOT NULL AND [l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL
) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id]
-WHERE EXISTS (
- SELECT 1
+WHERE 1 IN (
+ SELECT CASE
+ WHEN [t0].[Level2_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t0].[Id]
+ END
FROM (
SELECT DISTINCT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Level3_Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id]
FROM [Level1] AS [l1]
@@ -1869,9 +1875,7 @@ WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS
WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id]
END IS NULL AND [l1].[OneToMany_Optional_Inverse3Id] IS NULL))
) AS [t0]
- WHERE CASE
- WHEN [t0].[Level2_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t0].[Id]
- END = 1)
+)
""");
}
@@ -1958,8 +1962,8 @@ LEFT JOIN (
FROM [Level1] AS [l0]
WHERE [l0].[OneToOne_Required_PK_Date] IS NOT NULL AND [l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL
) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id]
-WHERE EXISTS (
- SELECT DISTINCT 1
+WHERE 1 IN (
+ SELECT DISTINCT CAST(LEN([l1].[Level3_Name]) AS int)
FROM [Level1] AS [l1]
WHERE [l1].[Level2_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse3Id] IS NOT NULL AND CASE
WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id]
@@ -1967,7 +1971,8 @@ END IS NOT NULL AND (CASE
WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id]
END = [l1].[OneToMany_Optional_Inverse3Id] OR (CASE
WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id]
- END IS NULL AND [l1].[OneToMany_Optional_Inverse3Id] IS NULL)) AND CAST(LEN([l1].[Level3_Name]) AS int) = 1)
+ END IS NULL AND [l1].[OneToMany_Optional_Inverse3Id] IS NULL))
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs
index dd571b961aa..8e8ffa09cc2 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs
@@ -144,12 +144,12 @@ public override async Task FromSqlRaw_composed_contains(bool async)
"""
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Orders"
) AS [m]
- WHERE [m].[CustomerID] = [c].[CustomerID])
+)
""");
}
@@ -161,12 +161,12 @@ public override async Task FromSqlRaw_composed_contains2(bool async)
"""
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] = N'ALFKI' AND EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] = N'ALFKI' AND [c].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Orders"
) AS [m]
- WHERE [m].[CustomerID] = [c].[CustomerID])
+)
""");
}
@@ -738,12 +738,12 @@ SELECT [m].[OrderID]
SELECT [o].[OrderID]
FROM [Orders] AS [o]
-WHERE [o].[OrderID] <= @__max_0 AND EXISTS (
- SELECT 1
+WHERE [o].[OrderID] <= @__max_0 AND [o].[OrderID] IN (
+ SELECT [m].[OrderID]
FROM (
SELECT * FROM "Orders" WHERE "OrderID" >= @p0
) AS [m]
- WHERE [m].[OrderID] = [o].[OrderID])
+)
""",
//
"""
@@ -752,12 +752,12 @@ SELECT 1
SELECT [o].[OrderID]
FROM [Orders] AS [o]
-WHERE [o].[OrderID] <= @__max_0 AND EXISTS (
- SELECT 1
+WHERE [o].[OrderID] <= @__max_0 AND [o].[OrderID] IN (
+ SELECT [m].[OrderID]
FROM (
SELECT * FROM "Orders" WHERE "OrderID" >= @p0
) AS [m]
- WHERE [m].[OrderID] = [o].[OrderID])
+)
""");
}
@@ -870,12 +870,12 @@ public override async Task FromSqlRaw_in_subquery_with_dbParameter(bool async)
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @city
) AS [m]
- WHERE [m].[CustomerID] = [o].[CustomerID])
+)
""");
}
@@ -889,12 +889,12 @@ public override async Task FromSqlRaw_in_subquery_with_positional_dbParameter_wi
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @p0
) AS [m]
- WHERE [m].[CustomerID] = [o].[CustomerID])
+)
""");
}
@@ -908,12 +908,12 @@ public override async Task FromSqlRaw_in_subquery_with_positional_dbParameter_wi
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @city
) AS [m]
- WHERE [m].[CustomerID] = [o].[CustomerID])
+)
""");
}
@@ -928,12 +928,12 @@ public override async Task FromSqlRaw_with_dbParameter_mixed_in_subquery(bool as
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @p0 AND "ContactTitle" = @title
) AS [m]
- WHERE [m].[CustomerID] = [o].[CustomerID])
+)
""",
//
"""
@@ -942,12 +942,12 @@ SELECT 1
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[CustomerID] IN (
+ SELECT [m].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @city AND "ContactTitle" = @p1
) AS [m]
- WHERE [m].[CustomerID] = [o].[CustomerID])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
index 111d5855b81..6198f19c203 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
@@ -2560,10 +2560,10 @@ public override async Task Optional_navigation_type_compensation_works_with_cont
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note]
FROM [Tags] AS [t]
LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId]
-WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND EXISTS (
- SELECT 1
+WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND [g].[SquadId] IN (
+ SELECT [g0].[SquadId]
FROM [Gears] AS [g0]
- WHERE [g0].[SquadId] = [g].[SquadId])
+)
""");
}
@@ -3106,10 +3106,10 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note]
FROM [Tags] AS [t]
-WHERE EXISTS (
- SELECT 1
+WHERE [t].[Id] IN (
+ SELECT CAST([i].[value] AS uniqueidentifier) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS uniqueidentifier) = [t].[Id])
+)
""");
}
@@ -6667,10 +6667,10 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a
SELECT [m].[Id], [m].[BriefingDocument], [m].[BriefingDocumentFileExtension], [m].[CodeName], [m].[Date], [m].[Duration], [m].[Rating], [m].[Time], [m].[Timeline]
FROM [Missions] AS [m]
-WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND EXISTS (
- SELECT 1
+WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND [m].[Timeline] IN (
+ SELECT CAST([d].[value] AS datetimeoffset) AS [value]
FROM OPENJSON(@__dates_2) AS [d]
- WHERE CAST([d].[value] AS datetimeoffset) = [m].[Timeline])
+)
""");
}
@@ -7382,10 +7382,10 @@ public override async Task OrderBy_Contains_empty_list(bool async)
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gears] AS [g]
ORDER BY CASE
- WHEN EXISTS (
- SELECT 1
+ WHEN [g].[SquadId] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [g].[SquadId]) THEN CAST(1 AS bit)
+ ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
""");
@@ -7933,10 +7933,10 @@ public override async Task Contains_on_collection_of_byte_subquery(bool async)
"""
SELECT [l].[Name], [l].[Discriminator], [l].[LocustHordeId], [l].[ThreatLevel], [l].[ThreatLevelByte], [l].[ThreatLevelNullableByte], [l].[DefeatedByNickname], [l].[DefeatedBySquadId], [l].[HighCommandId]
FROM [LocustLeaders] AS [l]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[ThreatLevelByte] IN (
+ SELECT [l0].[ThreatLevelByte]
FROM [LocustLeaders] AS [l0]
- WHERE [l0].[ThreatLevelByte] = [l].[ThreatLevelByte])
+)
""");
}
@@ -8010,10 +8010,10 @@ FROM [LocustLeaders] AS [l]
CROSS APPLY (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gears] AS [g]
- WHERE EXISTS (
- SELECT 1
+ WHERE [l].[ThreatLevelByte] IN (
+ SELECT [l0].[ThreatLevelByte]
FROM [LocustLeaders] AS [l0]
- WHERE [l0].[ThreatLevelByte] = [l].[ThreatLevelByte])
+ )
) AS [t]
""");
}
@@ -8030,10 +8030,10 @@ FROM [LocustLeaders] AS [l]
CROSS APPLY (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gears] AS [g]
- WHERE NOT EXISTS (
- SELECT 1
+ WHERE [l].[ThreatLevelByte] NOT IN (
+ SELECT [l0].[ThreatLevelByte]
FROM [LocustLeaders] AS [l0]
- WHERE [l0].[ThreatLevelByte] = [l].[ThreatLevelByte])
+ )
) AS [t]
""");
}
@@ -9379,10 +9379,10 @@ public override async Task Where_bool_column_and_Contains(bool async)
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gears] AS [g]
-WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [g].[HasSoulPatch])
+)
""");
}
@@ -9396,10 +9396,10 @@ public override async Task Where_bool_column_or_Contains(bool async)
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gears] AS [g]
-WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [g].[HasSoulPatch])
+)
""");
}
@@ -10097,8 +10097,8 @@ SELECT COALESCE(SUM(CAST(LEN([c].[Location]) AS int)), 0)
FROM [Gears] AS [g2]
INNER JOIN [Squads] AS [s0] ON [g2].[SquadId] = [s0].[Id]
INNER JOIN [Cities] AS [c] ON [g2].[CityOfBirthName] = [c].[Name]
- WHERE EXISTS (
- SELECT 1
+ WHERE N'Marcus' IN (
+ SELECT [t0].[Nickname]
FROM (
SELECT [g3].[Nickname], [g3].[SquadId], [g3].[AssignedCityName], [g3].[CityOfBirthName], [g3].[Discriminator], [g3].[FullName], [g3].[HasSoulPatch], [g3].[LeaderNickname], [g3].[LeaderSquadId], [g3].[Rank]
FROM [Gears] AS [g3]
@@ -10106,11 +10106,11 @@ UNION ALL
SELECT [g4].[Nickname], [g4].[SquadId], [g4].[AssignedCityName], [g4].[CityOfBirthName], [g4].[Discriminator], [g4].[FullName], [g4].[HasSoulPatch], [g4].[LeaderNickname], [g4].[LeaderSquadId], [g4].[Rank]
FROM [Gears] AS [g4]
) AS [t0]
- WHERE [t0].[Nickname] = N'Marcus') AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
+ ) AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
FROM [Gears] AS [g]
INNER JOIN [Squads] AS [s] ON [g].[SquadId] = [s].[Id]
-WHERE EXISTS (
- SELECT 1
+WHERE N'Marcus' IN (
+ SELECT [t].[Nickname]
FROM (
SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank]
FROM [Gears] AS [g0]
@@ -10118,7 +10118,7 @@ UNION ALL
SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank]
FROM [Gears] AS [g1]
) AS [t]
- WHERE [t].[Nickname] = N'Marcus')
+)
GROUP BY [s].[Name]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs
index 560225a1f9c..026de43e882 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs
@@ -303,13 +303,13 @@ public virtual async Task Same_parameter_with_different_type_mappings()
SELECT [t].[Id], [t].[DateTime], [t].[DateTime2], [t].[Ints]
FROM [TestEntity] AS [t]
-WHERE EXISTS (
- SELECT 1
+WHERE [t].[DateTime] IN (
+ SELECT CAST([d].[value] AS datetime) AS [value]
FROM OPENJSON(@__dateTimes_0) AS [d]
- WHERE CAST([d].[value] AS datetime) = [t].[DateTime]) AND EXISTS (
- SELECT 1
+) AND [t].[DateTime2] IN (
+ SELECT CAST([d0].[value] AS datetime2) AS [value]
FROM OPENJSON(@__dateTimes_0_1) AS [d0]
- WHERE CAST([d0].[value] AS datetime2) = [t].[DateTime2])
+)
""");
}
@@ -334,7 +334,7 @@ public virtual async Task Same_collection_with_conflicting_type_mappings_not_sup
m => dateTimes
.Any(d => d == EF.Property(m, "DateTime") && d == EF.Property(m, "DateTime2")))
.ToArrayAsync());
- Assert.Equal(RelationalStrings.ConflictingTypeMappingsForPrimitiveCollection("datetime2", "datetime"), exception.Message);
+ Assert.Equal(RelationalStrings.ConflictingTypeMappingsInferredForColumn("value"), exception.Message);
}
#endregion Type mapping inference
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs
index 3f459abd147..84cfe8b8efb 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs
@@ -1537,10 +1537,10 @@ public override async Task Contains_with_subquery(bool async)
"""
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT [o].[CustomerID]
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] = [c].[CustomerID])
+)
""");
}
@@ -1554,10 +1554,10 @@ public override async Task Contains_with_local_array_closure(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""",
//
"""
@@ -1565,10 +1565,10 @@ WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1616,10 +1616,10 @@ public override async Task Contains_with_local_uint_array_closure(bool async)
SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title]
FROM [Employees] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[EmployeeID] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[EmployeeID])
+)
""",
//
"""
@@ -1627,10 +1627,10 @@ WHERE CAST([i].[value] AS int) = [e].[EmployeeID])
SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title]
FROM [Employees] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[EmployeeID] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[EmployeeID])
+)
""");
}
@@ -1644,10 +1644,10 @@ public override async Task Contains_with_local_nullable_uint_array_closure(bool
SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title]
FROM [Employees] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[EmployeeID] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[EmployeeID])
+)
""",
//
"""
@@ -1655,10 +1655,10 @@ WHERE CAST([i].[value] AS int) = [e].[EmployeeID])
SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title]
FROM [Employees] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[EmployeeID] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[EmployeeID])
+)
""");
}
@@ -1684,10 +1684,10 @@ public override async Task Contains_with_local_list_closure(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1701,10 +1701,10 @@ public override async Task Contains_with_local_object_list_closure(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1718,10 +1718,10 @@ public override async Task Contains_with_local_list_closure_all_null(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1747,10 +1747,10 @@ public override async Task Contains_with_local_list_inline_closure_mix(bool asyn
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([p].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__p_0) AS [p]
- WHERE CAST([p].[value] AS nchar(5)) = [c].[CustomerID])
+)
""",
//
"""
@@ -1758,10 +1758,10 @@ WHERE CAST([p].[value] AS nchar(5)) = [c].[CustomerID])
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([p].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__p_0) AS [p]
- WHERE CAST([p].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1775,10 +1775,10 @@ public override async Task Contains_with_local_non_primitive_list_inline_closure
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([s].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__Select_0) AS [s]
- WHERE CAST([s].[value] AS nchar(5)) = [c].[CustomerID])
+)
""",
//
"""
@@ -1786,10 +1786,10 @@ WHERE CAST([s].[value] AS nchar(5)) = [c].[CustomerID])
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([s].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__Select_0) AS [s]
- WHERE CAST([s].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1803,10 +1803,10 @@ public override async Task Contains_with_local_non_primitive_list_closure_mix(bo
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([s].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__Select_0) AS [s]
- WHERE CAST([s].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1837,10 +1837,10 @@ public override async Task Contains_with_local_collection_complex_predicate_and(
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] IN (N'ALFKI', N'ABCDE') AND EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (N'ALFKI', N'ABCDE') AND [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1878,10 +1878,10 @@ public override async Task Contains_with_local_collection_sql_injection(bool asy
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID]) OR [c].[CustomerID] IN (N'ALFKI', N'ABCDE')
+) OR [c].[CustomerID] IN (N'ALFKI', N'ABCDE')
""");
}
@@ -1895,10 +1895,10 @@ public override async Task Contains_with_local_collection_empty_closure(bool asy
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -1922,10 +1922,10 @@ public override async Task Contains_top_level(bool async)
@__p_0='ALFKI' (Size = 5) (DbType = StringFixedLength)
SELECT CASE
- WHEN EXISTS (
- SELECT 1
+ WHEN @__p_0 IN (
+ SELECT [c].[CustomerID]
FROM [Customers] AS [c]
- WHERE [c].[CustomerID] = @__p_0) THEN CAST(1 AS bit)
+ ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
""");
@@ -2353,10 +2353,10 @@ public override async Task Where_subquery_any_equals_operator(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -2382,10 +2382,10 @@ public override async Task Where_subquery_any_equals_static(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
@@ -2399,10 +2399,10 @@ public override async Task Where_subquery_where_any(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[City] = N'México D.F.' AND EXISTS (
- SELECT 1
+WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""",
//
"""
@@ -2410,10 +2410,10 @@ WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[City] = N'México D.F.' AND EXISTS (
- SELECT 1
+WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] IN (
+ SELECT CAST([i].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs
index 471826b8fdd..0b0146fc71c 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs
@@ -182,10 +182,10 @@ public override void Query_with_contains()
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([a].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__args) AS [a]
- WHERE CAST([a].[value] AS nchar(5)) = [c].[CustomerID])
+)
""",
//
"""
@@ -193,10 +193,10 @@ WHERE CAST([a].[value] AS nchar(5)) = [c].[CustomerID])
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([a].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__args) AS [a]
- WHERE CAST([a].[value] AS nchar(5)) = [c].[CustomerID])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs
index dd3be5d7c6d..f59f8df4023 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs
@@ -2724,10 +2724,10 @@ public override async Task Where_subquery_on_bool(bool async)
"""
SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock]
FROM [Products] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE N'Chai' IN (
+ SELECT [p0].[ProductName]
FROM [Products] AS [p0]
- WHERE [p0].[ProductName] = N'Chai')
+)
""");
}
@@ -2739,10 +2739,11 @@ public override async Task Where_subquery_on_collection(bool async)
"""
SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock]
FROM [Products] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE CAST(5 AS smallint) IN (
+ SELECT [o].[Quantity]
FROM [Order Details] AS [o]
- WHERE [o].[ProductID] = [p].[ProductID] AND [o].[Quantity] = CAST(5 AS smallint))
+ WHERE [o].[ProductID] = [p].[ProductID]
+)
""");
}
@@ -4039,10 +4040,10 @@ public override async Task Contains_with_DateTime_Date(bool async)
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE CONVERT(date, [o].[OrderDate]) IN (
+ SELECT CAST([d].[value] AS datetime) AS [value]
FROM OPENJSON(@__dates_0) AS [d]
- WHERE CAST([d].[value] AS datetime) = CONVERT(date, [o].[OrderDate]))
+)
""",
//
"""
@@ -4050,10 +4051,10 @@ WHERE CAST([d].[value] AS datetime) = CONVERT(date, [o].[OrderDate]))
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE CONVERT(date, [o].[OrderDate]) IN (
+ SELECT CAST([d].[value] AS datetime) AS [value]
FROM OPENJSON(@__dates_0) AS [d]
- WHERE CAST([d].[value] AS datetime) = CONVERT(date, [o].[OrderDate]))
+)
""");
}
@@ -4065,11 +4066,12 @@ public override async Task Contains_with_subquery_involving_join_binds_to_correc
"""
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE [o].[OrderID] > 11000 AND EXISTS (
- SELECT 1
+WHERE [o].[OrderID] > 11000 AND [o].[OrderID] IN (
+ SELECT [o0].[OrderID]
FROM [Order Details] AS [o0]
INNER JOIN [Products] AS [p] ON [o0].[ProductID] = [p].[ProductID]
- WHERE [p].[ProductName] = N'Chai' AND [o0].[OrderID] = [o].[OrderID])
+ WHERE [p].[ProductName] = N'Chai'
+)
""");
}
@@ -6274,10 +6276,10 @@ FROM [Customers] AS [c]
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Orders] AS [o]
LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[OrderID] IN (
+ SELECT CAST([o0].[value] AS int) AS [value]
FROM OPENJSON(@__orderIds_0) AS [o0]
- WHERE CAST([o0].[value] AS int) = [o].[OrderID])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs
index 5bb41fbeb7c..33b317711d1 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs
@@ -784,10 +784,10 @@ LEFT JOIN (
SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[CustomerID] AS [CustomerID0], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID], [c0].[CustomerID]) AS [row]
FROM [Orders] AS [o]
LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID]
- WHERE EXISTS (
- SELECT 1
+ WHERE [o].[OrderID] IN (
+ SELECT CAST([o0].[value] AS int) AS [value]
FROM OPENJSON(@__orderIds_0) AS [o0]
- WHERE CAST([o0].[value] AS int) = [o].[OrderID])
+ )
) AS [t]
WHERE [t].[row] <= 1
) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID0]
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs
index 14a62d6a3bf..73d3cb6b16b 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs
@@ -2089,10 +2089,10 @@ FROM [Orders] AS [o]
OUTER APPLY (
SELECT [t].[CustomerID], [o0].[OrderID], [o0].[OrderDate]
FROM [Orders] AS [o0]
- WHERE [t].[CustomerID] IS NOT NULL AND [t].[CustomerID] = [o0].[CustomerID] AND EXISTS (
- SELECT 1
+ WHERE [t].[CustomerID] IS NOT NULL AND [t].[CustomerID] = [o0].[CustomerID] AND [o0].[OrderID] IN (
+ SELECT CAST([f].[value] AS int) AS [value]
FROM OPENJSON(@__filteredOrderIds_0) AS [f]
- WHERE CAST([f].[value] AS int) = [o0].[OrderID])
+ )
) AS [t0]
ORDER BY [t].[CustomerID], [t0].[OrderID]
""");
@@ -2114,10 +2114,10 @@ FROM [Orders] AS [o]
OUTER APPLY (
SELECT [t].[OrderID] AS [Outer], [o0].[OrderID] AS [Inner], [o0].[OrderDate]
FROM [Orders] AS [o0]
- WHERE [o0].[OrderID] = [t].[OrderID] AND EXISTS (
- SELECT 1
+ WHERE [o0].[OrderID] = [t].[OrderID] AND [o0].[OrderID] IN (
+ SELECT CAST([f].[value] AS int) AS [value]
FROM OPENJSON(@__filteredOrderIds_0) AS [f]
- WHERE CAST([f].[value] AS int) = [o0].[OrderID])
+ )
) AS [t0]
ORDER BY [t].[OrderID]
""");
@@ -2139,10 +2139,10 @@ FROM [Orders] AS [o]
OUTER APPLY (
SELECT [t].[OrderDate] AS [Outer1], [t].[CustomerID] AS [Outer2], [o0].[OrderID] AS [Inner], [o0].[OrderDate]
FROM [Orders] AS [o0]
- WHERE ([o0].[CustomerID] = [t].[CustomerID] OR ([o0].[CustomerID] IS NULL AND [t].[CustomerID] IS NULL)) AND EXISTS (
- SELECT 1
+ WHERE ([o0].[CustomerID] = [t].[CustomerID] OR ([o0].[CustomerID] IS NULL AND [t].[CustomerID] IS NULL)) AND [o0].[OrderID] IN (
+ SELECT CAST([f].[value] AS int) AS [value]
FROM OPENJSON(@__filteredOrderIds_0) AS [f]
- WHERE CAST([f].[value] AS int) = [o0].[OrderID])
+ )
) AS [t0]
ORDER BY [t].[OrderDate], [t].[CustomerID]
""");
@@ -2180,10 +2180,10 @@ FROM [Orders] AS [o]
OUTER APPLY (
SELECT [t0].[OrderID] AS [Outer], [o0].[OrderID] AS [Inner], [o0].[OrderDate]
FROM [Orders] AS [o0]
- WHERE [o0].[OrderID] = [t0].[OrderID] AND EXISTS (
- SELECT 1
+ WHERE [o0].[OrderID] = [t0].[OrderID] AND [o0].[OrderID] IN (
+ SELECT CAST([f].[value] AS int) AS [value]
FROM OPENJSON(@__filteredOrderIds_0) AS [f]
- WHERE CAST([f].[value] AS int) = [o0].[OrderID])
+ )
) AS [t1]
ORDER BY [t0].[OrderID]
""");
@@ -2620,10 +2620,10 @@ FROM [Orders] AS [o]
OUTER APPLY (
SELECT [t0].[CustomerID] AS [Outer], [o0].[OrderID] AS [Inner], [o0].[OrderDate]
FROM [Orders] AS [o0]
- WHERE ([o0].[CustomerID] = [t0].[CustomerID] OR ([o0].[CustomerID] IS NULL AND [t0].[CustomerID] IS NULL)) AND EXISTS (
- SELECT 1
+ WHERE ([o0].[CustomerID] = [t0].[CustomerID] OR ([o0].[CustomerID] IS NULL AND [t0].[CustomerID] IS NULL)) AND [o0].[OrderID] IN (
+ SELECT CAST([f].[value] AS int) AS [value]
FROM OPENJSON(@__filteredOrderIds_0) AS [f]
- WHERE CAST([f].[value] AS int) = [o0].[OrderID])
+ )
) AS [t1]
ORDER BY [t0].[CustomerID], [t0].[Complex]
""");
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSqlQuerySqlServerTest.cs
index 996eb55ff57..0220c2b5d22 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSqlQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSqlQuerySqlServerTest.cs
@@ -35,12 +35,12 @@ public override async Task SqlQuery_composed_Contains(bool async)
"""
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[OrderID] IN (
+ SELECT [t].[Value]
FROM (
SELECT "ProductID" AS "Value" FROM "Products"
) AS [t]
- WHERE CAST([t].[Value] AS int) = [o].[OrderID])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs
index 4e68138bfe5..709c4acbb67 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs
@@ -1897,21 +1897,15 @@ public override async Task Where_multiple_contains_in_subquery_with_or(bool asyn
"""
SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice]
FROM [Order Details] AS [o]
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT TOP(1) [p].[ProductID]
- FROM [Products] AS [p]
- ORDER BY [p].[ProductID]
- ) AS [t]
- WHERE [t].[ProductID] = [o].[ProductID]) OR EXISTS (
- SELECT 1
- FROM (
- SELECT TOP(1) [o0].[OrderID]
- FROM [Orders] AS [o0]
- ORDER BY [o0].[OrderID]
- ) AS [t0]
- WHERE [t0].[OrderID] = [o].[OrderID])
+WHERE [o].[ProductID] IN (
+ SELECT TOP(1) [p].[ProductID]
+ FROM [Products] AS [p]
+ ORDER BY [p].[ProductID]
+) OR [o].[OrderID] IN (
+ SELECT TOP(1) [o0].[OrderID]
+ FROM [Orders] AS [o0]
+ ORDER BY [o0].[OrderID]
+)
""");
}
@@ -1923,21 +1917,15 @@ public override async Task Where_multiple_contains_in_subquery_with_and(bool asy
"""
SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice]
FROM [Order Details] AS [o]
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT TOP(20) [p].[ProductID]
- FROM [Products] AS [p]
- ORDER BY [p].[ProductID]
- ) AS [t]
- WHERE [t].[ProductID] = [o].[ProductID]) AND EXISTS (
- SELECT 1
- FROM (
- SELECT TOP(10) [o0].[OrderID]
- FROM [Orders] AS [o0]
- ORDER BY [o0].[OrderID]
- ) AS [t0]
- WHERE [t0].[OrderID] = [o].[OrderID])
+WHERE [o].[ProductID] IN (
+ SELECT TOP(20) [p].[ProductID]
+ FROM [Products] AS [p]
+ ORDER BY [p].[ProductID]
+) AND [o].[OrderID] IN (
+ SELECT TOP(10) [o0].[OrderID]
+ FROM [Orders] AS [o0]
+ ORDER BY [o0].[OrderID]
+)
""");
}
@@ -2171,10 +2159,11 @@ public override async Task Where_Queryable_ToList_Contains(bool async)
SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID]
FROM [Customers] AS [c]
LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID]
-WHERE EXISTS (
- SELECT 1
+WHERE N'ALFKI' IN (
+ SELECT [o].[CustomerID]
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] = [c].[CustomerID] AND [o].[CustomerID] = N'ALFKI')
+ WHERE [o].[CustomerID] = [c].[CustomerID]
+)
ORDER BY [c].[CustomerID]
""");
}
@@ -2205,10 +2194,11 @@ public override async Task Where_Queryable_ToArray_Contains(bool async)
SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID]
FROM [Customers] AS [c]
LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID]
-WHERE EXISTS (
- SELECT 1
+WHERE N'ALFKI' IN (
+ SELECT [o].[CustomerID]
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] = [c].[CustomerID] AND [o].[CustomerID] = N'ALFKI')
+ WHERE [o].[CustomerID] = [c].[CustomerID]
+)
ORDER BY [c].[CustomerID]
""");
}
@@ -2239,10 +2229,11 @@ public override async Task Where_Queryable_AsEnumerable_Contains(bool async)
SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID]
FROM [Customers] AS [c]
LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID]
-WHERE EXISTS (
- SELECT 1
+WHERE N'ALFKI' IN (
+ SELECT [o].[CustomerID]
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] = [c].[CustomerID] AND [o].[CustomerID] = N'ALFKI')
+ WHERE [o].[CustomerID] = [c].[CustomerID]
+)
ORDER BY [c].[CustomerID]
""");
}
@@ -2450,10 +2441,10 @@ public override async Task Where_list_object_contains_over_value_type(bool async
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[OrderID] IN (
+ SELECT CAST([o0].[value] AS int) AS [value]
FROM OPENJSON(@__orderIds_0) AS [o0]
- WHERE CAST([o0].[value] AS int) = [o].[OrderID])
+)
""");
}
@@ -2467,10 +2458,10 @@ public override async Task Where_array_of_object_contains_over_value_type(bool a
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate]
FROM [Orders] AS [o]
-WHERE EXISTS (
- SELECT 1
+WHERE [o].[OrderID] IN (
+ SELECT CAST([o0].[value] AS int) AS [value]
FROM OPENJSON(@__orderIds_0) AS [o0]
- WHERE CAST([o0].[value] AS int) = [o].[OrderID])
+)
""");
}
@@ -2574,10 +2565,10 @@ public override async Task Array_of_parameters_Contains_OrElse_comparison_with_c
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([p].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__p_0) AS [p]
- WHERE CAST([p].[value] AS nchar(5)) = [c].[CustomerID]) OR [c].[CustomerID] = N'ANTON'
+) OR [c].[CustomerID] = N'ANTON'
""");
}
@@ -2604,10 +2595,10 @@ public override async Task Parameter_array_Contains_OrElse_comparison_with_const
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([a].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__array_0) AS [a]
- WHERE CAST([a].[value] AS nchar(5)) = [c].[CustomerID]) OR [c].[CustomerID] = N'ANTON'
+) OR [c].[CustomerID] = N'ANTON'
""");
}
@@ -2623,10 +2614,10 @@ public override async Task Parameter_array_Contains_OrElse_comparison_with_param
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] = @__prm1_0 OR EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] = @__prm1_0 OR [c].[CustomerID] IN (
+ SELECT CAST([a].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__array_1) AS [a]
- WHERE CAST([a].[value] AS nchar(5)) = [c].[CustomerID]) OR [c].[CustomerID] = @__prm2_2
+) OR [c].[CustomerID] = @__prm2_2
""");
}
@@ -2932,10 +2923,10 @@ public override async Task Where_Contains_and_comparison(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([c0].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__customerIds_0) AS [c0]
- WHERE CAST([c0].[value] AS nchar(5)) = [c].[CustomerID]) AND [c].[City] = N'Seattle'
+) AND [c].[City] = N'Seattle'
""");
}
@@ -2949,10 +2940,10 @@ public override async Task Where_Contains_or_comparison(bool async)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE EXISTS (
- SELECT 1
+WHERE [c].[CustomerID] IN (
+ SELECT CAST([c0].[value] AS nchar(5)) AS [value]
FROM OPENJSON(@__customerIds_0) AS [c0]
- WHERE CAST([c0].[value] AS nchar(5)) = [c].[CustomerID]) OR [c].[City] = N'Seattle'
+) OR [c].[City] = N'Seattle'
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs
index 79c6dc8fbc6..6aa94446969 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs
@@ -1247,10 +1247,10 @@ public override async Task Where_conditional_search_condition_in_result(bool asy
SELECT [e].[Id]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[StringA] IN (
+ SELECT [l].[value]
FROM OPENJSON(@__list_0) AS [l]
- WHERE [l].[value] = [e].[StringA])
+)
""",
//
"""
@@ -1293,10 +1293,10 @@ public override void Where_contains_on_parameter_array_with_relational_null_sema
SELECT [e].[NullableStringA]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[NullableStringA] IN (
+ SELECT [n].[value]
FROM OPENJSON(@__names_0) AS [n]
- WHERE [n].[value] = [e].[NullableStringA])
+)
""");
}
@@ -1310,10 +1310,10 @@ public override void Where_contains_on_parameter_empty_array_with_relational_nul
SELECT [e].[NullableStringA]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[NullableStringA] IN (
+ SELECT [n].[value]
FROM OPENJSON(@__names_0) AS [n]
- WHERE [n].[value] = [e].[NullableStringA])
+)
""");
}
@@ -1327,10 +1327,10 @@ public override void Where_contains_on_parameter_array_with_just_null_with_relat
SELECT [e].[NullableStringA]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[NullableStringA] IN (
+ SELECT [n].[value]
FROM OPENJSON(@__names_0) AS [n]
- WHERE [n].[value] = [e].[NullableStringA])
+)
""");
}
@@ -1921,20 +1921,116 @@ WHERE [e].[NullableIntA] IS NOT NULL
""");
}
- public override async Task Null_semantics_contains_non_nullable_argument(bool async)
+ public override async Task Null_semantics_contains_non_nullable_item_with_non_nullable_subquery(bool async)
{
- await base.Null_semantics_contains_non_nullable_argument(async);
+ await base.Null_semantics_contains_non_nullable_item_with_non_nullable_subquery(async);
AssertSql(
"""
-@__ids_0='[1,2,null]' (Size = 4000)
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE [e].[StringA] IN (
+ SELECT [e0].[StringA]
+ FROM [Entities2] AS [e0]
+)
+""",
+ //
+"""
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE [e].[StringA] NOT IN (
+ SELECT [e0].[StringA]
+ FROM [Entities2] AS [e0]
+)
+""");
+ }
+
+ public override async Task Null_semantics_contains_nullable_item_with_non_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_nullable_item_with_non_nullable_subquery(async);
+
+ AssertSql(
+"""
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE [e].[NullableStringA] IN (
+ SELECT [e0].[StringA]
+ FROM [Entities2] AS [e0]
+)
+""",
+ //
+"""
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE [e].[NullableStringA] NOT IN (
+ SELECT [e0].[StringA]
+ FROM [Entities2] AS [e0]
+) OR [e].[NullableStringA] IS NULL
+""");
+ }
+
+ public override async Task Null_semantics_contains_non_nullable_item_with_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_non_nullable_item_with_nullable_subquery(async);
+
+ AssertSql(
+"""
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE [e].[StringA] IN (
+ SELECT [e0].[NullableStringA]
+ FROM [Entities2] AS [e0]
+)
+""",
+ //
+"""
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM [Entities2] AS [e0]
+ WHERE [e0].[NullableStringA] = [e].[StringA])
+""");
+ }
+
+ public override async Task Null_semantics_contains_nullable_item_with_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_nullable_item_with_nullable_subquery(async);
+ AssertSql(
+"""
SELECT [e].[Id]
FROM [Entities1] AS [e]
WHERE EXISTS (
SELECT 1
+ FROM [Entities2] AS [e0]
+ WHERE [e0].[NullableStringA] = [e].[NullableStringA] OR ([e0].[NullableStringA] IS NULL AND [e].[NullableStringA] IS NULL))
+""",
+ //
+"""
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM [Entities2] AS [e0]
+ WHERE [e0].[NullableStringA] = [e].[NullableStringA] OR ([e0].[NullableStringA] IS NULL AND [e].[NullableStringA] IS NULL))
+""");
+ }
+
+ public override async Task Null_semantics_contains_non_nullable_item_with_values(bool async)
+ {
+ await base.Null_semantics_contains_non_nullable_item_with_values(async);
+
+ AssertSql(
+"""
+@__ids_0='[1,2,null]' (Size = 4000)
+
+SELECT [e].[Id]
+FROM [Entities1] AS [e]
+WHERE [e].[IntA] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[IntA])
+)
""",
//
"""
@@ -1953,10 +2049,10 @@ WHERE CAST([i].[value] AS int) = [e].[IntA])
SELECT [e].[Id]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[IntA] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids2_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[IntA])
+)
""",
//
"""
@@ -1975,10 +2071,10 @@ WHERE CAST([i].[value] AS int) = [e].[IntA])
SELECT [e].[Id]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[IntA] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids3_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[IntA])
+)
""",
//
"""
@@ -1997,10 +2093,10 @@ WHERE CAST([i].[value] AS int) = [e].[IntA])
SELECT [e].[Id]
FROM [Entities1] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[IntA] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids4_0) AS [i]
- WHERE CAST([i].[value] AS int) = [e].[IntA])
+)
""",
//
"""
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
index 0748763df67..69813a78a1f 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
@@ -193,31 +193,31 @@ public override Task Parameter_collection_Count(bool async)
public override async Task Parameter_collection_of_ints_Contains(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_int(async);
AssertSql(
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE [p].[NullableInt] IN (10, 999)
+WHERE [p].[Int] IN (10, 999)
""");
}
- public override async Task Parameter_collection_of_nullable_ints_Contains(bool async)
+ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_int(async);
AssertSql(
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE [p].[NullableInt] IN (10, 999)
+WHERE [p].[Int] IN (10, 999)
""");
}
- public override async Task Parameter_collection_of_nullable_ints_Contains_null(bool async)
+ public override async Task Parameter_collection_of_nullable_ints_Contains_nullable_int(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains_null(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_nullable_int(async);
AssertSql(
"""
@@ -296,6 +296,9 @@ public override Task Column_collection_of_nullable_ints_Contains(bool async)
public override Task Column_collection_of_nullable_ints_Contains_null(bool async)
=> AssertTranslationFailed(() => base.Column_collection_of_nullable_ints_Contains_null(async));
+ public override Task Column_collection_of_strings_contains_null(bool async)
+ => AssertTranslationFailed(() => base.Column_collection_of_strings_contains_null(async));
+
public override Task Column_collection_of_bools_Contains(bool async)
=> AssertTranslationFailed(() => base.Column_collection_of_bools_Contains(async));
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs
index 6dff82ec517..9580116c856 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs
@@ -152,10 +152,10 @@ public override async Task Inline_collection_Contains_with_all_parameters(bool a
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[Id] IN (
+ SELECT CAST([p0].[value] AS int) AS [value]
FROM OPENJSON(@__p_0) AS [p0]
- WHERE CAST([p0].[value] AS int) = [p].[Id])
+)
""");
}
@@ -217,16 +217,16 @@ public override async Task Parameter_collection_of_ints_Contains(bool async)
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[Int] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ints_0) AS [i]
- WHERE CAST([i].[value] AS int) = [p].[Int])
+)
""");
}
- public override async Task Parameter_collection_of_nullable_ints_Contains(bool async)
+ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_int(async);
AssertSql(
"""
@@ -234,16 +234,16 @@ public override async Task Parameter_collection_of_nullable_ints_Contains(bool a
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[Int] IN (
+ SELECT CAST([n].[value] AS int) AS [value]
FROM OPENJSON(@__nullableInts_0) AS [n]
- WHERE CAST([n].[value] AS int) = [p].[NullableInt] OR ([n].[value] IS NULL AND [p].[NullableInt] IS NULL))
+)
""");
}
- public override async Task Parameter_collection_of_nullable_ints_Contains_null(bool async)
+ public override async Task Parameter_collection_of_nullable_ints_Contains_nullable_int(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains_null(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_nullable_int(async);
AssertSql(
"""
@@ -285,10 +285,10 @@ public override async Task Parameter_collection_of_DateTimes_Contains(bool async
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[DateTime] IN (
+ SELECT CAST([d].[value] AS datetime) AS [value]
FROM OPENJSON(@__dateTimes_0) AS [d]
- WHERE CAST([d].[value] AS datetime) = [p].[DateTime])
+)
""");
}
@@ -302,10 +302,10 @@ public override async Task Parameter_collection_of_bools_Contains(bool async)
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[Bool] IN (
+ SELECT CAST([b].[value] AS bit) AS [value]
FROM OPENJSON(@__bools_0) AS [b]
- WHERE CAST([b].[value] AS bit) = [p].[Bool])
+)
""");
}
@@ -319,10 +319,10 @@ public override async Task Parameter_collection_of_enums_Contains(bool async)
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[Enum] IN (
+ SELECT CAST([e].[value] AS int) AS [value]
FROM OPENJSON(@__enums_0) AS [e]
- WHERE CAST([e].[value] AS int) = [p].[Enum])
+)
""");
}
@@ -334,10 +334,10 @@ public override async Task Parameter_collection_null_Contains(bool async)
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE [p].[Int] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(N'[]') AS [i]
- WHERE CAST([i].[value] AS int) = [p].[Int])
+)
""");
}
@@ -349,10 +349,10 @@ public override async Task Column_collection_of_ints_Contains(bool async)
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE 10 IN (
+ SELECT CAST([i].[value] AS int)
FROM OPENJSON([p].[Ints]) AS [i]
- WHERE CAST([i].[value] AS int) = 10)
+)
""");
}
@@ -364,10 +364,10 @@ public override async Task Column_collection_of_nullable_ints_Contains(bool asyn
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
+WHERE 10 IN (
+ SELECT CAST([n].[value] AS int)
FROM OPENJSON([p].[NullableInts]) AS [n]
- WHERE CAST([n].[value] AS int) = 10)
+)
""");
}
@@ -386,9 +386,9 @@ FROM OPENJSON([p].[NullableInts]) AS [n]
""");
}
- public override async Task Column_collection_of_bools_Contains(bool async)
+ public override async Task Column_collection_of_strings_contains_null(bool async)
{
- await base.Column_collection_of_bools_Contains(async);
+ await base.Column_collection_of_strings_contains_null(async);
AssertSql(
"""
@@ -396,8 +396,23 @@ public override async Task Column_collection_of_bools_Contains(bool async)
FROM [PrimitiveCollectionsEntity] AS [p]
WHERE EXISTS (
SELECT 1
+ FROM OPENJSON([p].[Strings]) AS [s]
+ WHERE [s].[value] IS NULL)
+""");
+ }
+
+ public override async Task Column_collection_of_bools_Contains(bool async)
+ {
+ await base.Column_collection_of_bools_Contains(async);
+
+ AssertSql(
+"""
+SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
+FROM [PrimitiveCollectionsEntity] AS [p]
+WHERE CAST(1 AS bit) IN (
+ SELECT CAST([b].[value] AS bit)
FROM OPENJSON([p].[Bools]) AS [b]
- WHERE CAST([b].[value] AS bit) = CAST(1 AS bit))
+)
""");
}
@@ -572,14 +587,11 @@ public override async Task Column_collection_Take(bool async)
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT TOP(2) CAST([i].[value] AS int) AS [c], CAST([i].[key] AS int) AS [c0]
- FROM OPENJSON([p].[Ints]) AS [i]
- ORDER BY CAST([i].[key] AS int)
- ) AS [t]
- WHERE [t].[c] = 11)
+WHERE 11 IN (
+ SELECT TOP(2) CAST([i].[value] AS int)
+ FROM OPENJSON([p].[Ints]) AS [i]
+ ORDER BY CAST([i].[key] AS int)
+)
""");
}
@@ -591,15 +603,12 @@ public override async Task Column_collection_Skip_Take(bool async)
"""
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[String], [p].[Strings]
FROM [PrimitiveCollectionsEntity] AS [p]
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT CAST([i].[value] AS int) AS [c], CAST([i].[key] AS int) AS [c0]
- FROM OPENJSON([p].[Ints]) AS [i]
- ORDER BY CAST([i].[key] AS int)
- OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY
- ) AS [t]
- WHERE [t].[c] = 11)
+WHERE 11 IN (
+ SELECT CAST([i].[value] AS int)
+ FROM OPENJSON([p].[Ints]) AS [i]
+ ORDER BY CAST([i].[key] AS int)
+ OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
index 34d2f662f12..bc5c98a4123 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
@@ -186,40 +186,40 @@ public async Task Where_contains_DateTime_literals(bool async)
SELECT [d].[Id], [d].[DateTime], [d].[DateTime2], [d].[DateTime2_0], [d].[DateTime2_1], [d].[DateTime2_2], [d].[DateTime2_3], [d].[DateTime2_4], [d].[DateTime2_5], [d].[DateTime2_6], [d].[DateTime2_7], [d].[SmallDateTime]
FROM [Dates] AS [d]
-WHERE EXISTS (
- SELECT 1
+WHERE [d].[SmallDateTime] IN (
+ SELECT CAST([d0].[value] AS smalldatetime) AS [value]
FROM OPENJSON(@__dateTimes_0) AS [d0]
- WHERE CAST([d0].[value] AS smalldatetime) = [d].[SmallDateTime]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime] IN (
+ SELECT CAST([d1].[value] AS datetime) AS [value]
FROM OPENJSON(@__dateTimes_0_1) AS [d1]
- WHERE CAST([d1].[value] AS datetime) = [d].[DateTime]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2] IN (
+ SELECT CAST([d2].[value] AS datetime2) AS [value]
FROM OPENJSON(@__dateTimes_0_2) AS [d2]
- WHERE CAST([d2].[value] AS datetime2) = [d].[DateTime2]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_0] IN (
+ SELECT CAST([d3].[value] AS datetime2(0)) AS [value]
FROM OPENJSON(@__dateTimes_0_3) AS [d3]
- WHERE CAST([d3].[value] AS datetime2(0)) = [d].[DateTime2_0]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_1] IN (
+ SELECT CAST([d4].[value] AS datetime2(1)) AS [value]
FROM OPENJSON(@__dateTimes_0_4) AS [d4]
- WHERE CAST([d4].[value] AS datetime2(1)) = [d].[DateTime2_1]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_2] IN (
+ SELECT CAST([d5].[value] AS datetime2(2)) AS [value]
FROM OPENJSON(@__dateTimes_0_5) AS [d5]
- WHERE CAST([d5].[value] AS datetime2(2)) = [d].[DateTime2_2]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_3] IN (
+ SELECT CAST([d6].[value] AS datetime2(3)) AS [value]
FROM OPENJSON(@__dateTimes_0_6) AS [d6]
- WHERE CAST([d6].[value] AS datetime2(3)) = [d].[DateTime2_3]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_4] IN (
+ SELECT CAST([d7].[value] AS datetime2(4)) AS [value]
FROM OPENJSON(@__dateTimes_0_7) AS [d7]
- WHERE CAST([d7].[value] AS datetime2(4)) = [d].[DateTime2_4]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_5] IN (
+ SELECT CAST([d8].[value] AS datetime2(5)) AS [value]
FROM OPENJSON(@__dateTimes_0_8) AS [d8]
- WHERE CAST([d8].[value] AS datetime2(5)) = [d].[DateTime2_5]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_6] IN (
+ SELECT CAST([d9].[value] AS datetime2(6)) AS [value]
FROM OPENJSON(@__dateTimes_0_9) AS [d9]
- WHERE CAST([d9].[value] AS datetime2(6)) = [d].[DateTime2_6]) AND EXISTS (
- SELECT 1
+) AND [d].[DateTime2_7] IN (
+ SELECT CAST([d10].[value] AS datetime2(7)) AS [value]
FROM OPENJSON(@__dateTimes_0_10) AS [d10]
- WHERE CAST([d10].[value] AS datetime2(7)) = [d].[DateTime2_7])
+)
""");
}
@@ -2091,10 +2091,11 @@ FROM [Entities] AS [e]
SELECT [e].[Id], [e].[Name]
FROM [Entities] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[Id] IN (
+ SELECT [e0].[Id]
FROM [Entities] AS [e0]
- WHERE [e0].[Id] = @__id_0 AND [e0].[Id] = [e].[Id])
+ WHERE [e0].[Id] = @__id_0
+)
""",
//
"""
@@ -2102,10 +2103,11 @@ FROM [Entities] AS [e0]
SELECT [e].[Id], [e].[Name]
FROM [Entities] AS [e]
-WHERE EXISTS (
- SELECT 1
+WHERE [e].[Id] IN (
+ SELECT [e0].[Id]
FROM [Entities] AS [e0]
- WHERE [e0].[Id] = @__id_0 AND [e0].[Id] = [e].[Id])
+ WHERE [e0].[Id] = @__id_0
+)
""");
}
}
@@ -3922,10 +3924,10 @@ public virtual async Task DateTime_Contains_with_smalldatetime_generates_correct
SELECT [r].[Id], [r].[MyTime]
FROM [ReproEntity] AS [r]
-WHERE EXISTS (
- SELECT 1
+WHERE [r].[MyTime] IN (
+ SELECT CAST([t].[value] AS smalldatetime) AS [value]
FROM OPENJSON(@__testDateList_0) AS [t]
- WHERE CAST([t].[value] AS smalldatetime) = [r].[MyTime])
+)
""");
}
}
@@ -3973,6 +3975,8 @@ public virtual async Task Nested_contains_with_enum()
var keys = new List { Guid.Parse("0a47bcb7-a1cb-4345-8944-c58f82d6aac7"), key };
var todoTypes = new List { MyContext12732.TodoType.foo0 };
+ // Note that in this query, the outer Contains really has no type mapping, neither for its source (collection parameter), nor
+ // for its item (the conditional expression returns key, which is also a parameter). The default type mapping must be applied.
var query = context.Todos
.Where(x => keys.Contains(todoTypes.Contains(x.Type) ? key : key))
.ToList();
@@ -3981,18 +3985,18 @@ public virtual async Task Nested_contains_with_enum()
AssertSql(
"""
-@__keys_0='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000)
@__key_2='5f221fb9-66f4-442a-92c9-d97ed5989cc7'
+@__keys_0='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000)
SELECT [t].[Id], [t].[Type]
FROM [Todos] AS [t]
-WHERE EXISTS (
- SELECT 1
+WHERE CASE
+ WHEN [t].[Type] = 0 THEN @__key_2
+ ELSE @__key_2
+END IN (
+ SELECT CAST([k].[value] AS uniqueidentifier) AS [value]
FROM OPENJSON(@__keys_0) AS [k]
- WHERE CAST([k].[value] AS uniqueidentifier) = CASE
- WHEN [t].[Type] = 0 THEN @__key_2
- ELSE @__key_2
- END)
+)
""");
}
}
@@ -8894,10 +8898,10 @@ public virtual async Task Query_filter_with_contains_evaluates_correctly()
SELECT [e].[Id], [e].[Name]
FROM [Entities] AS [e]
-WHERE NOT EXISTS (
- SELECT 1
+WHERE [e].[Id] NOT IN (
+ SELECT CAST([e0].[value] AS int) AS [value]
FROM OPENJSON(@__ef_filter___ids_0) AS [e0]
- WHERE CAST([e0].[value] AS int) = [e].[Id])
+)
""");
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs
index 0b5d828b399..4a3adbbe67e 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs
@@ -96,10 +96,10 @@ public override void DbContext_list_is_parameterized()
"""
SELECT [l].[Id], [l].[Tenant]
FROM [ListFilter] AS [l]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[Tenant] IN (
+ SELECT CAST([e].[value] AS int) AS [value]
FROM OPENJSON(N'[]') AS [e]
- WHERE CAST([e].[value] AS int) = [l].[Tenant])
+)
""",
//
"""
@@ -107,10 +107,10 @@ WHERE CAST([e].[value] AS int) = [l].[Tenant])
SELECT [l].[Id], [l].[Tenant]
FROM [ListFilter] AS [l]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[Tenant] IN (
+ SELECT CAST([e].[value] AS int) AS [value]
FROM OPENJSON(@__ef_filter__TenantIds_0) AS [e]
- WHERE CAST([e].[value] AS int) = [l].[Tenant])
+)
""",
//
"""
@@ -118,10 +118,10 @@ WHERE CAST([e].[value] AS int) = [l].[Tenant])
SELECT [l].[Id], [l].[Tenant]
FROM [ListFilter] AS [l]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[Tenant] IN (
+ SELECT CAST([e].[value] AS int) AS [value]
FROM OPENJSON(@__ef_filter__TenantIds_0) AS [e]
- WHERE CAST([e].[value] AS int) = [l].[Tenant])
+)
""",
//
"""
@@ -129,10 +129,10 @@ WHERE CAST([e].[value] AS int) = [l].[Tenant])
SELECT [l].[Id], [l].[Tenant]
FROM [ListFilter] AS [l]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[Tenant] IN (
+ SELECT CAST([e].[value] AS int) AS [value]
FROM OPENJSON(@__ef_filter__TenantIds_0) AS [e]
- WHERE CAST([e].[value] AS int) = [l].[Tenant])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs
index 9b24b8e6149..47447b5838e 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs
@@ -135,10 +135,11 @@ WHEN EXISTS (
SELECT 1
FROM [Memberships] AS [m]
INNER JOIN [Users] AS [u0] ON [m].[UserId] = [u0].[Id]
- WHERE EXISTS (
- SELECT 1
+ WHERE [m].[GroupId] IN (
+ SELECT [m0].[GroupId]
FROM [Memberships] AS [m0]
- WHERE [m0].[UserId] = @__currentUserId_0 AND [m0].[GroupId] = [m].[GroupId]) AND [u0].[Id] = [u].[Id]) THEN CAST(1 AS bit)
+ WHERE [m0].[UserId] = @__currentUserId_0
+ ) AND [u0].[Id] = [u].[Id]) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [HasAccess]
FROM [Users] AS [u]
@@ -183,10 +184,11 @@ WHEN EXISTS (
SELECT 1
FROM [Memberships] AS [m]
INNER JOIN [Users] AS [u0] ON [m].[UserId] = [u0].[Id]
- WHERE EXISTS (
- SELECT 1
+ WHERE [m].[GroupId] IN (
+ SELECT [m0].[GroupId]
FROM [Memberships] AS [m0]
- WHERE [m0].[UserId] = @__currentUserId_0 AND [m0].[GroupId] = [m].[GroupId]) AND [u0].[Id] = [u].[Id]) THEN CAST(1 AS bit)
+ WHERE [m0].[UserId] = @__currentUserId_0
+ ) AND [u0].[Id] = [u].[Id]) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [HasAccess]
FROM [Users] AS [u]
@@ -562,12 +564,12 @@ public virtual async Task Muliple_occurrences_of_FromSql_in_group_by_aggregate(b
SELECT [d].[Id] AS [Key], COUNT(*) AS [Aggregate]
FROM [DemoEntities] AS [d]
-WHERE EXISTS (
- SELECT 1
+WHERE [d].[Id] IN (
+ SELECT [m].[Id]
FROM (
SELECT * FROM DemoEntities WHERE Id = @p0
) AS [m]
- WHERE [m].[Id] = [d].[Id])
+)
GROUP BY [d].[Id]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs
index 2d2b9ecc76a..9af4d2a0e32 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs
@@ -141,17 +141,17 @@ public override async Task SqlQueryRaw_composed_contains(bool async)
await base.SqlQueryRaw_composed_contains(async);
AssertSql(
- """
+"""
SELECT [m].[Address], [m].[City], [m].[CompanyName], [m].[ContactName], [m].[ContactTitle], [m].[Country], [m].[CustomerID], [m].[Fax], [m].[Phone], [m].[Region], [m].[PostalCode]
FROM (
SELECT * FROM "Customers"
) AS [m]
-WHERE EXISTS (
- SELECT 1
+WHERE [m].[CustomerID] IN (
+ SELECT [m0].[CustomerID]
FROM (
SELECT * FROM "Orders"
) AS [m0]
- WHERE [m0].[CustomerID] = [m].[CustomerID])
+)
""");
}
@@ -553,7 +553,7 @@ public override async Task SqlQuery_parameterization_issue_12213(bool async)
await base.SqlQuery_parameterization_issue_12213(async);
AssertSql(
- """
+"""
p0='10300'
SELECT [m].[OrderID]
@@ -562,7 +562,7 @@ SELECT [m].[OrderID]
) AS [m]
""",
//
- """
+"""
@__max_1='10400'
p0='10300'
@@ -570,15 +570,15 @@ SELECT [m].[OrderID]
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE [m].[OrderID] <= @__max_1 AND EXISTS (
- SELECT 1
+WHERE [m].[OrderID] <= @__max_1 AND [m].[OrderID] IN (
+ SELECT [m0].[OrderID]
FROM (
SELECT * FROM "Orders" WHERE "OrderID" >= @p0
) AS [m0]
- WHERE [m0].[OrderID] = [m].[OrderID])
+)
""",
//
- """
+"""
@__max_1='10400'
p0='10300'
@@ -586,12 +586,12 @@ SELECT [m].[OrderID]
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE [m].[OrderID] <= @__max_1 AND EXISTS (
- SELECT 1
+WHERE [m].[OrderID] <= @__max_1 AND [m].[OrderID] IN (
+ SELECT [m0].[OrderID]
FROM (
SELECT * FROM "Orders" WHERE "OrderID" >= @p0
) AS [m0]
- WHERE [m0].[OrderID] = [m].[OrderID])
+)
""");
}
@@ -645,19 +645,19 @@ public override async Task SqlQueryRaw_in_subquery_with_dbParameter(bool async)
await base.SqlQueryRaw_in_subquery_with_dbParameter(async);
AssertSql(
- """
+"""
@city='London' (Nullable = false) (Size = 6)
SELECT [m].[CustomerID], [m].[EmployeeID], [m].[Freight], [m].[OrderDate], [m].[OrderID], [m].[RequiredDate], [m].[ShipAddress], [m].[ShipCity], [m].[ShipCountry], [m].[ShipName], [m].[ShipPostalCode], [m].[ShipRegion], [m].[ShipVia], [m].[ShippedDate]
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE EXISTS (
- SELECT 1
+WHERE [m].[CustomerID] IN (
+ SELECT [m0].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @city
) AS [m0]
- WHERE [m0].[CustomerID] = [m].[CustomerID])
+)
""");
}
@@ -666,19 +666,19 @@ public override async Task SqlQueryRaw_in_subquery_with_positional_dbParameter_w
await base.SqlQueryRaw_in_subquery_with_positional_dbParameter_without_name(async);
AssertSql(
- """
+"""
p0='London' (Nullable = false) (Size = 6)
SELECT [m].[CustomerID], [m].[EmployeeID], [m].[Freight], [m].[OrderDate], [m].[OrderID], [m].[RequiredDate], [m].[ShipAddress], [m].[ShipCity], [m].[ShipCountry], [m].[ShipName], [m].[ShipPostalCode], [m].[ShipRegion], [m].[ShipVia], [m].[ShippedDate]
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE EXISTS (
- SELECT 1
+WHERE [m].[CustomerID] IN (
+ SELECT [m0].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @p0
) AS [m0]
- WHERE [m0].[CustomerID] = [m].[CustomerID])
+)
""");
}
@@ -687,19 +687,19 @@ public override async Task SqlQueryRaw_in_subquery_with_positional_dbParameter_w
await base.SqlQueryRaw_in_subquery_with_positional_dbParameter_with_name(async);
AssertSql(
- """
+"""
@city='London' (Nullable = false) (Size = 6)
SELECT [m].[CustomerID], [m].[EmployeeID], [m].[Freight], [m].[OrderDate], [m].[OrderID], [m].[RequiredDate], [m].[ShipAddress], [m].[ShipCity], [m].[ShipCountry], [m].[ShipName], [m].[ShipPostalCode], [m].[ShipRegion], [m].[ShipVia], [m].[ShippedDate]
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE EXISTS (
- SELECT 1
+WHERE [m].[CustomerID] IN (
+ SELECT [m0].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @city
) AS [m0]
- WHERE [m0].[CustomerID] = [m].[CustomerID])
+)
""");
}
@@ -708,7 +708,7 @@ public override async Task SqlQueryRaw_with_dbParameter_mixed_in_subquery(bool a
await base.SqlQueryRaw_with_dbParameter_mixed_in_subquery(async);
AssertSql(
- """
+"""
p0='London' (Size = 4000)
@title='Sales Representative' (Nullable = false) (Size = 20)
@@ -716,15 +716,15 @@ public override async Task SqlQueryRaw_with_dbParameter_mixed_in_subquery(bool a
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE EXISTS (
- SELECT 1
+WHERE [m].[CustomerID] IN (
+ SELECT [m0].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @p0 AND "ContactTitle" = @title
) AS [m0]
- WHERE [m0].[CustomerID] = [m].[CustomerID])
+)
""",
//
- """
+"""
@city='London' (Nullable = false) (Size = 6)
p1='Sales Representative' (Size = 4000)
@@ -732,12 +732,12 @@ SELECT 1
FROM (
SELECT * FROM "Orders"
) AS [m]
-WHERE EXISTS (
- SELECT 1
+WHERE [m].[CustomerID] IN (
+ SELECT [m0].[CustomerID]
FROM (
SELECT * FROM "Customers" WHERE "City" = @city AND "ContactTitle" = @p1
) AS [m0]
- WHERE [m0].[CustomerID] = [m].[CustomerID])
+)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
index 043be0c6f33..82d63243b8f 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
@@ -3573,16 +3573,13 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId]
FROM [Officers] AS [o]
) AS [t0] ON [t].[GearNickName] = [t0].[Nickname] AND [t].[GearSquadId] = [t0].[SquadId]
-WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND EXISTS (
- SELECT 1
- FROM (
- SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], N'Gear' AS [Discriminator]
- FROM [Gears] AS [g0]
- UNION ALL
- SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator]
- FROM [Officers] AS [o0]
- ) AS [t1]
- WHERE [t1].[SquadId] = [t0].[SquadId])
+WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND [t0].[SquadId] IN (
+ SELECT [g0].[SquadId]
+ FROM [Gears] AS [g0]
+ UNION ALL
+ SELECT [o0].[SquadId]
+ FROM [Officers] AS [o0]
+)
""");
}
@@ -4148,10 +4145,10 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note]
FROM [Tags] AS [t]
-WHERE EXISTS (
- SELECT 1
+WHERE [t].[Id] IN (
+ SELECT CAST([i].[value] AS uniqueidentifier) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS uniqueidentifier) = [t].[Id])
+)
""");
}
@@ -8963,10 +8960,10 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a
SELECT [m].[Id], [m].[CodeName], [m].[Date], [m].[Duration], [m].[Rating], [m].[Time], [m].[Timeline]
FROM [Missions] AS [m]
-WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND EXISTS (
- SELECT 1
+WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND [m].[Timeline] IN (
+ SELECT CAST([d].[value] AS datetimeoffset) AS [value]
FROM OPENJSON(@__dates_2) AS [d]
- WHERE CAST([d].[value] AS datetimeoffset) = [m].[Timeline])
+)
""");
}
@@ -9844,10 +9841,10 @@ UNION ALL
FROM [Officers] AS [o]
) AS [t]
ORDER BY CASE
- WHEN EXISTS (
- SELECT 1
+ WHEN [t].[SquadId] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [t].[SquadId]) THEN CAST(1 AS bit)
+ ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
""");
@@ -10514,16 +10511,13 @@ UNION ALL
SELECT [l0].[Name], [l0].[LocustHordeId], [l0].[ThreatLevel], [l0].[ThreatLevelByte], [l0].[ThreatLevelNullableByte], [l0].[DefeatedByNickname], [l0].[DefeatedBySquadId], [l0].[HighCommandId], N'LocustCommander' AS [Discriminator]
FROM [LocustCommanders] AS [l0]
) AS [t]
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
- FROM [LocustLeaders] AS [l1]
- UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
- FROM [LocustCommanders] AS [l2]
- ) AS [t0]
- WHERE [t0].[ThreatLevelByte] = [t].[ThreatLevelByte])
+WHERE [t].[ThreatLevelByte] IN (
+ SELECT [l1].[ThreatLevelByte]
+ FROM [LocustLeaders] AS [l1]
+ UNION ALL
+ SELECT [l2].[ThreatLevelByte]
+ FROM [LocustCommanders] AS [l2]
+)
""");
}
@@ -10544,10 +10538,10 @@ FROM [LocustCommanders] AS [l0]
WHERE EXISTS (
SELECT 1
FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
+ SELECT [l1].[ThreatLevelNullableByte]
FROM [LocustLeaders] AS [l1]
UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
+ SELECT [l2].[ThreatLevelNullableByte]
FROM [LocustCommanders] AS [l2]
) AS [t0]
WHERE [t0].[ThreatLevelNullableByte] = [t].[ThreatLevelNullableByte] OR ([t0].[ThreatLevelNullableByte] IS NULL AND [t].[ThreatLevelNullableByte] IS NULL))
@@ -10571,10 +10565,10 @@ FROM [LocustCommanders] AS [l0]
WHERE EXISTS (
SELECT 1
FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
+ SELECT [l1].[ThreatLevelNullableByte]
FROM [LocustLeaders] AS [l1]
UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
+ SELECT [l2].[ThreatLevelNullableByte]
FROM [LocustCommanders] AS [l2]
) AS [t0]
WHERE [t0].[ThreatLevelNullableByte] IS NULL)
@@ -10598,10 +10592,10 @@ FROM [LocustCommanders] AS [l0]
WHERE EXISTS (
SELECT 1
FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
+ SELECT [l1].[ThreatLevelNullableByte]
FROM [LocustLeaders] AS [l1]
UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
+ SELECT [l2].[ThreatLevelNullableByte]
FROM [LocustCommanders] AS [l2]
) AS [t0]
WHERE [t0].[ThreatLevelNullableByte] IS NULL)
@@ -10651,16 +10645,13 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
FROM [Officers] AS [o]
) AS [t0]
- WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
- FROM [LocustLeaders] AS [l1]
- UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
- FROM [LocustCommanders] AS [l2]
- ) AS [t2]
- WHERE [t2].[ThreatLevelByte] = [t].[ThreatLevelByte])
+ WHERE [t].[ThreatLevelByte] IN (
+ SELECT [l1].[ThreatLevelByte]
+ FROM [LocustLeaders] AS [l1]
+ UNION ALL
+ SELECT [l2].[ThreatLevelByte]
+ FROM [LocustCommanders] AS [l2]
+ )
) AS [t1]
""");
}
@@ -10689,16 +10680,13 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
FROM [Officers] AS [o]
) AS [t0]
- WHERE NOT EXISTS (
- SELECT 1
- FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
- FROM [LocustLeaders] AS [l1]
- UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
- FROM [LocustCommanders] AS [l2]
- ) AS [t2]
- WHERE [t2].[ThreatLevelByte] = [t].[ThreatLevelByte])
+ WHERE [t].[ThreatLevelByte] NOT IN (
+ SELECT [l1].[ThreatLevelByte]
+ FROM [LocustLeaders] AS [l1]
+ UNION ALL
+ SELECT [l2].[ThreatLevelByte]
+ FROM [LocustCommanders] AS [l2]
+ )
) AS [t1]
""");
}
@@ -10729,10 +10717,10 @@ FROM [Officers] AS [o]
WHERE EXISTS (
SELECT 1
FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
+ SELECT [l1].[ThreatLevelNullableByte]
FROM [LocustLeaders] AS [l1]
UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
+ SELECT [l2].[ThreatLevelNullableByte]
FROM [LocustCommanders] AS [l2]
) AS [t2]
WHERE [t2].[ThreatLevelNullableByte] = [t].[ThreatLevelNullableByte] OR ([t2].[ThreatLevelNullableByte] IS NULL AND [t].[ThreatLevelNullableByte] IS NULL))
@@ -10766,10 +10754,10 @@ FROM [Officers] AS [o]
WHERE NOT EXISTS (
SELECT 1
FROM (
- SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator]
+ SELECT [l1].[ThreatLevelNullableByte]
FROM [LocustLeaders] AS [l1]
UNION ALL
- SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator]
+ SELECT [l2].[ThreatLevelNullableByte]
FROM [LocustCommanders] AS [l2]
) AS [t2]
WHERE [t2].[ThreatLevelNullableByte] = [t].[ThreatLevelNullableByte] OR ([t2].[ThreatLevelNullableByte] IS NULL AND [t].[ThreatLevelNullableByte] IS NULL))
@@ -11975,10 +11963,10 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
FROM [Officers] AS [o]
) AS [t]
-WHERE [t].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [t].[HasSoulPatch] = CAST(1 AS bit) AND [t].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [t].[HasSoulPatch])
+)
""");
}
@@ -11998,10 +11986,10 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
FROM [Officers] AS [o]
) AS [t]
-WHERE [t].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [t].[HasSoulPatch] = CAST(1 AS bit) AND [t].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [t].[HasSoulPatch])
+)
""");
}
@@ -13285,8 +13273,8 @@ FROM [Officers] AS [o0]
) AS [t3]
INNER JOIN [Squads] AS [s0] ON [t3].[SquadId] = [s0].[Id]
INNER JOIN [Cities] AS [c] ON [t3].[CityOfBirthName] = [c].[Name]
- WHERE EXISTS (
- SELECT 1
+ WHERE N'Marcus' IN (
+ SELECT [t4].[Nickname]
FROM (
SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank], N'Gear' AS [Discriminator]
FROM [Gears] AS [g1]
@@ -13300,7 +13288,7 @@ UNION ALL
SELECT [o2].[Nickname], [o2].[SquadId], [o2].[AssignedCityName], [o2].[CityOfBirthName], [o2].[FullName], [o2].[HasSoulPatch], [o2].[LeaderNickname], [o2].[LeaderSquadId], [o2].[Rank], N'Officer' AS [Discriminator]
FROM [Officers] AS [o2]
) AS [t4]
- WHERE [t4].[Nickname] = N'Marcus') AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
+ ) AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
FROM (
SELECT [g].[SquadId]
FROM [Gears] AS [g]
@@ -13309,8 +13297,8 @@ SELECT [o].[SquadId]
FROM [Officers] AS [o]
) AS [t]
INNER JOIN [Squads] AS [s] ON [t].[SquadId] = [s].[Id]
-WHERE EXISTS (
- SELECT 1
+WHERE N'Marcus' IN (
+ SELECT [t0].[Nickname]
FROM (
SELECT [g3].[Nickname], [g3].[SquadId], [g3].[AssignedCityName], [g3].[CityOfBirthName], [g3].[FullName], [g3].[HasSoulPatch], [g3].[LeaderNickname], [g3].[LeaderSquadId], [g3].[Rank], N'Gear' AS [Discriminator]
FROM [Gears] AS [g3]
@@ -13324,7 +13312,7 @@ UNION ALL
SELECT [o4].[Nickname], [o4].[SquadId], [o4].[AssignedCityName], [o4].[CityOfBirthName], [o4].[FullName], [o4].[HasSoulPatch], [o4].[LeaderNickname], [o4].[LeaderSquadId], [o4].[Rank], N'Officer' AS [Discriminator]
FROM [Officers] AS [o4]
) AS [t0]
- WHERE [t0].[Nickname] = N'Marcus')
+)
GROUP BY [s].[Name]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
index 7849b346fe6..069db1c2802 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
@@ -3058,11 +3058,11 @@ LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId]
FROM [Gears] AS [g]
) AS [t0] ON [t].[GearNickName] = [t0].[Nickname] AND [t].[GearSquadId] = [t0].[SquadId]
-WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND EXISTS (
- SELECT 1
+WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND [t0].[SquadId] IN (
+ SELECT [g0].[SquadId]
FROM [Gears] AS [g0]
LEFT JOIN [Officers] AS [o0] ON [g0].[Nickname] = [o0].[Nickname] AND [g0].[SquadId] = [o0].[SquadId]
- WHERE [g0].[SquadId] = [t0].[SquadId])
+)
""");
}
@@ -3569,10 +3569,10 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note]
FROM [Tags] AS [t]
-WHERE EXISTS (
- SELECT 1
+WHERE [t].[Id] IN (
+ SELECT CAST([i].[value] AS uniqueidentifier) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS uniqueidentifier) = [t].[Id])
+)
""");
}
@@ -7626,10 +7626,10 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a
SELECT [m].[Id], [m].[CodeName], [m].[Date], [m].[Duration], [m].[Rating], [m].[Time], [m].[Timeline]
FROM [Missions] AS [m]
-WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND EXISTS (
- SELECT 1
+WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND [m].[Timeline] IN (
+ SELECT CAST([d].[value] AS datetimeoffset) AS [value]
FROM OPENJSON(@__dates_2) AS [d]
- WHERE CAST([d].[value] AS datetimeoffset) = [m].[Timeline])
+)
""");
}
@@ -8436,10 +8436,10 @@ END AS [Discriminator]
FROM [Gears] AS [g]
LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
ORDER BY CASE
- WHEN EXISTS (
- SELECT 1
+ WHEN [g].[SquadId] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [g].[SquadId]) THEN CAST(1 AS bit)
+ ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
""");
@@ -9034,11 +9034,11 @@ WHEN [l0].[Name] IS NOT NULL THEN N'LocustCommander'
END AS [Discriminator]
FROM [LocustLeaders] AS [l]
LEFT JOIN [LocustCommanders] AS [l0] ON [l].[Name] = [l0].[Name]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[ThreatLevelByte] IN (
+ SELECT [l1].[ThreatLevelByte]
FROM [LocustLeaders] AS [l1]
LEFT JOIN [LocustCommanders] AS [l2] ON [l1].[Name] = [l2].[Name]
- WHERE [l1].[ThreatLevelByte] = [l].[ThreatLevelByte])
+)
""");
}
@@ -9133,11 +9133,11 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
END AS [Discriminator]
FROM [Gears] AS [g]
LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
- WHERE EXISTS (
- SELECT 1
+ WHERE [l].[ThreatLevelByte] IN (
+ SELECT [l1].[ThreatLevelByte]
FROM [LocustLeaders] AS [l1]
LEFT JOIN [LocustCommanders] AS [l2] ON [l1].[Name] = [l2].[Name]
- WHERE [l1].[ThreatLevelByte] = [l].[ThreatLevelByte])
+ )
) AS [t]
""");
}
@@ -9157,11 +9157,11 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
END AS [Discriminator]
FROM [Gears] AS [g]
LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
- WHERE NOT EXISTS (
- SELECT 1
+ WHERE [l].[ThreatLevelByte] NOT IN (
+ SELECT [l1].[ThreatLevelByte]
FROM [LocustLeaders] AS [l1]
LEFT JOIN [LocustCommanders] AS [l2] ON [l1].[Name] = [l2].[Name]
- WHERE [l1].[ThreatLevelByte] = [l].[ThreatLevelByte])
+ )
) AS [t]
""");
}
@@ -10264,10 +10264,10 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
END AS [Discriminator]
FROM [Gears] AS [g]
LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
-WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [g].[HasSoulPatch])
+)
""");
}
@@ -10284,10 +10284,10 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
END AS [Discriminator]
FROM [Gears] AS [g]
LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
-WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [g].[HasSoulPatch])
+)
""");
}
@@ -11436,8 +11436,8 @@ FROM [Gears] AS [g2]
LEFT JOIN [Officers] AS [o2] ON [g2].[Nickname] = [o2].[Nickname] AND [g2].[SquadId] = [o2].[SquadId]
INNER JOIN [Squads] AS [s0] ON [g2].[SquadId] = [s0].[Id]
INNER JOIN [Cities] AS [c] ON [g2].[CityOfBirthName] = [c].[Name]
- WHERE EXISTS (
- SELECT 1
+ WHERE N'Marcus' IN (
+ SELECT [t0].[Nickname]
FROM (
SELECT [g3].[Nickname], [g3].[SquadId], [g3].[AssignedCityName], [g3].[CityOfBirthName], [g3].[FullName], [g3].[HasSoulPatch], [g3].[LeaderNickname], [g3].[LeaderSquadId], [g3].[Rank], CASE
WHEN [o3].[Nickname] IS NOT NULL THEN N'Officer'
@@ -11451,11 +11451,11 @@ END AS [Discriminator]
FROM [Gears] AS [g4]
LEFT JOIN [Officers] AS [o4] ON [g4].[Nickname] = [o4].[Nickname] AND [g4].[SquadId] = [o4].[SquadId]
) AS [t0]
- WHERE [t0].[Nickname] = N'Marcus') AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
+ ) AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
FROM [Gears] AS [g]
INNER JOIN [Squads] AS [s] ON [g].[SquadId] = [s].[Id]
-WHERE EXISTS (
- SELECT 1
+WHERE N'Marcus' IN (
+ SELECT [t].[Nickname]
FROM (
SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], CASE
WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer'
@@ -11469,7 +11469,7 @@ END AS [Discriminator]
FROM [Gears] AS [g1]
LEFT JOIN [Officers] AS [o1] ON [g1].[Nickname] = [o1].[Nickname] AND [g1].[SquadId] = [o1].[SquadId]
) AS [t]
- WHERE [t].[Nickname] = N'Marcus')
+)
GROUP BY [s].[Name]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
index 3da4aa91429..966ebefd564 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
@@ -1632,10 +1632,10 @@ public override async Task Where_bool_column_or_Contains(bool async)
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
-WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [g].[HasSoulPatch])
+)
""");
}
@@ -2947,10 +2947,10 @@ public override async Task Subquery_projecting_non_nullable_scalar_contains_non_
CROSS APPLY (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
- WHERE NOT EXISTS (
- SELECT 1
+ WHERE [l].[ThreatLevelByte] NOT IN (
+ SELECT [l0].[ThreatLevelByte]
FROM [LocustLeaders] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0]
- WHERE [l0].[ThreatLevelByte] = [l].[ThreatLevelByte])
+ )
) AS [t]
""");
}
@@ -3513,10 +3513,10 @@ public override async Task Contains_on_collection_of_byte_subquery(bool async)
"""
SELECT [l].[Name], [l].[Discriminator], [l].[LocustHordeId], [l].[PeriodEnd], [l].[PeriodStart], [l].[ThreatLevel], [l].[ThreatLevelByte], [l].[ThreatLevelNullableByte], [l].[DefeatedByNickname], [l].[DefeatedBySquadId], [l].[HighCommandId]
FROM [LocustLeaders] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l]
-WHERE EXISTS (
- SELECT 1
+WHERE [l].[ThreatLevelByte] IN (
+ SELECT [l0].[ThreatLevelByte]
FROM [LocustLeaders] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0]
- WHERE [l0].[ThreatLevelByte] = [l].[ThreatLevelByte])
+)
""");
}
@@ -4062,10 +4062,10 @@ public override async Task Subquery_projecting_non_nullable_scalar_contains_non_
CROSS APPLY (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
- WHERE EXISTS (
- SELECT 1
+ WHERE [l].[ThreatLevelByte] IN (
+ SELECT [l0].[ThreatLevelByte]
FROM [LocustLeaders] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0]
- WHERE [l0].[ThreatLevelByte] = [l].[ThreatLevelByte])
+ )
) AS [t]
""");
}
@@ -6163,10 +6163,10 @@ public override async Task OrderBy_Contains_empty_list(bool async)
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
ORDER BY CASE
- WHEN EXISTS (
- SELECT 1
+ WHEN [g].[SquadId] IN (
+ SELECT CAST([i].[value] AS int) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS int) = [g].[SquadId]) THEN CAST(1 AS bit)
+ ) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
""");
@@ -6283,10 +6283,10 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a
SELECT [m].[Id], [m].[BriefingDocument], [m].[BriefingDocumentFileExtension], [m].[CodeName], [m].[Date], [m].[Duration], [m].[PeriodEnd], [m].[PeriodStart], [m].[Rating], [m].[Time], [m].[Timeline]
FROM [Missions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [m]
-WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND EXISTS (
- SELECT 1
+WHERE @__start_0 <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @__end_1 AND [m].[Timeline] IN (
+ SELECT CAST([d].[value] AS datetimeoffset) AS [value]
FROM OPENJSON(@__dates_2) AS [d]
- WHERE CAST([d].[value] AS datetimeoffset) = [m].[Timeline])
+)
""");
}
@@ -6637,10 +6637,10 @@ public override async Task Optional_navigation_type_compensation_works_with_cont
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart]
FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t]
LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId]
-WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND EXISTS (
- SELECT 1
+WHERE ([t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL) AND [g].[SquadId] IN (
+ SELECT [g0].[SquadId]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0]
- WHERE [g0].[SquadId] = [g].[SquadId])
+)
""");
}
@@ -8303,10 +8303,10 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart]
FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t]
-WHERE EXISTS (
- SELECT 1
+WHERE [t].[Id] IN (
+ SELECT CAST([i].[value] AS uniqueidentifier) AS [value]
FROM OPENJSON(@__ids_0) AS [i]
- WHERE CAST([i].[value] AS uniqueidentifier) = [t].[Id])
+)
""");
}
@@ -8961,10 +8961,10 @@ public override async Task Where_bool_column_and_Contains(bool async)
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
-WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND EXISTS (
- SELECT 1
+WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (
+ SELECT CAST([v].[value] AS bit) AS [value]
FROM OPENJSON(@__values_0) AS [v]
- WHERE CAST([v].[value] AS bit) = [g].[HasSoulPatch])
+)
""");
}
@@ -10003,8 +10003,8 @@ SELECT COALESCE(SUM(CAST(LEN([c].[Location]) AS int)), 0)
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g2]
INNER JOIN [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s0] ON [g2].[SquadId] = [s0].[Id]
INNER JOIN [Cities] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [c] ON [g2].[CityOfBirthName] = [c].[Name]
- WHERE EXISTS (
- SELECT 1
+ WHERE N'Marcus' IN (
+ SELECT [t0].[Nickname]
FROM (
SELECT [g3].[Nickname], [g3].[SquadId], [g3].[AssignedCityName], [g3].[CityOfBirthName], [g3].[Discriminator], [g3].[FullName], [g3].[HasSoulPatch], [g3].[LeaderNickname], [g3].[LeaderSquadId], [g3].[PeriodEnd], [g3].[PeriodStart], [g3].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g3]
@@ -10012,11 +10012,11 @@ UNION ALL
SELECT [g4].[Nickname], [g4].[SquadId], [g4].[AssignedCityName], [g4].[CityOfBirthName], [g4].[Discriminator], [g4].[FullName], [g4].[HasSoulPatch], [g4].[LeaderNickname], [g4].[LeaderSquadId], [g4].[PeriodEnd], [g4].[PeriodStart], [g4].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g4]
) AS [t0]
- WHERE [t0].[Nickname] = N'Marcus') AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
+ ) AND ([s].[Name] = [s0].[Name] OR ([s].[Name] IS NULL AND [s0].[Name] IS NULL))) AS [SumOfLengths]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
INNER JOIN [Squads] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] ON [g].[SquadId] = [s].[Id]
-WHERE EXISTS (
- SELECT 1
+WHERE N'Marcus' IN (
+ SELECT [t].[Nickname]
FROM (
SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[PeriodEnd], [g0].[PeriodStart], [g0].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0]
@@ -10024,7 +10024,7 @@ UNION ALL
SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[PeriodEnd], [g1].[PeriodStart], [g1].[Rank]
FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g1]
) AS [t]
- WHERE [t].[Nickname] = N'Marcus')
+)
GROUP BY [s].[Name]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
index aeb735fce1b..a61cfc6485b 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
@@ -935,22 +935,22 @@ SELECT COALESCE(SUM(CAST(LEN([c2].[FirstName]) AS int)), 0)
FROM [Orders] AS [o0]
INNER JOIN [Customers] AS [c1] ON [o0].[CustomerId] = [c1].[Id]
INNER JOIN [Customers] AS [c2] ON [o0].[CustomerId] = [c2].[Id]
- WHERE NOT EXISTS (
- SELECT 1
+ WHERE 25 NOT IN (
+ SELECT [g0].[CustomerId]
FROM [dbo].[GetOrdersWithMultipleProducts]((
SELECT TOP(1) [c3].[Id]
FROM [Customers] AS [c3]
ORDER BY [c3].[Id])) AS [g0]
- WHERE [g0].[CustomerId] = 25) AND ([c0].[LastName] = [c1].[LastName] OR ([c0].[LastName] IS NULL AND [c1].[LastName] IS NULL))) AS [SumOfLengths]
+ ) AND ([c0].[LastName] = [c1].[LastName] OR ([c0].[LastName] IS NULL AND [c1].[LastName] IS NULL))) AS [SumOfLengths]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c0] ON [o].[CustomerId] = [c0].[Id]
-WHERE NOT EXISTS (
- SELECT 1
+WHERE 25 NOT IN (
+ SELECT [g].[CustomerId]
FROM [dbo].[GetOrdersWithMultipleProducts]((
SELECT TOP(1) [c].[Id]
FROM [Customers] AS [c]
ORDER BY [c].[Id])) AS [g]
- WHERE [g].[CustomerId] = 25)
+)
GROUP BY [c0].[LastName]
""");
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
index be87fb50ab5..74e138fd71b 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
@@ -1904,10 +1904,10 @@ public override async Task Correlated_collection_with_complex_order_by_funcletiz
SELECT "g"."Nickname", "g"."SquadId", "w"."Name", "w"."Id"
FROM "Gears" AS "g"
LEFT JOIN "Weapons" AS "w" ON "g"."FullName" = "w"."OwnerFullName"
-ORDER BY EXISTS (
- SELECT 1
+ORDER BY COALESCE("g"."Nickname" IN (
+ SELECT "n"."value"
FROM json_each(@__nicknames_0) AS "n"
- WHERE "n"."value" = "g"."Nickname") DESC, "g"."Nickname", "g"."SquadId"
+), 0) DESC, "g"."Nickname", "g"."SquadId"
""");
}
@@ -2168,10 +2168,10 @@ public override async Task Where_bool_column_and_Contains(bool async)
SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank"
FROM "Gears" AS "g"
-WHERE "g"."HasSoulPatch" AND EXISTS (
- SELECT 1
+WHERE "g"."HasSoulPatch" AND "g"."HasSoulPatch" IN (
+ SELECT "v"."value"
FROM json_each(@__values_0) AS "v"
- WHERE "v"."value" = "g"."HasSoulPatch")
+)
""");
}
@@ -2408,10 +2408,10 @@ public override async Task Optional_navigation_type_compensation_works_with_cont
SELECT "t"."Id", "t"."GearNickName", "t"."GearSquadId", "t"."IssueDate", "t"."Note"
FROM "Tags" AS "t"
LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId"
-WHERE ("t"."Note" <> 'K.I.A.' OR "t"."Note" IS NULL) AND EXISTS (
- SELECT 1
+WHERE ("t"."Note" <> 'K.I.A.' OR "t"."Note" IS NULL) AND "g"."SquadId" IN (
+ SELECT "g0"."SquadId"
FROM "Gears" AS "g0"
- WHERE "g0"."SquadId" = "g"."SquadId")
+)
""");
}
@@ -4170,10 +4170,10 @@ public override async Task Contains_on_collection_of_byte_subquery(bool async)
"""
SELECT "l"."Name", "l"."Discriminator", "l"."LocustHordeId", "l"."ThreatLevel", "l"."ThreatLevelByte", "l"."ThreatLevelNullableByte", "l"."DefeatedByNickname", "l"."DefeatedBySquadId", "l"."HighCommandId"
FROM "LocustLeaders" AS "l"
-WHERE EXISTS (
- SELECT 1
+WHERE "l"."ThreatLevelByte" IN (
+ SELECT "l0"."ThreatLevelByte"
FROM "LocustLeaders" AS "l0"
- WHERE "l0"."ThreatLevelByte" = "l"."ThreatLevelByte")
+)
""");
}
@@ -4505,10 +4505,10 @@ public override async Task Where_bool_column_or_Contains(bool async)
SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank"
FROM "Gears" AS "g"
-WHERE "g"."HasSoulPatch" AND EXISTS (
- SELECT 1
+WHERE "g"."HasSoulPatch" AND "g"."HasSoulPatch" IN (
+ SELECT "v"."value"
FROM json_each(@__values_0) AS "v"
- WHERE "v"."value" = "g"."HasSoulPatch")
+)
""");
}
@@ -5594,10 +5594,10 @@ public override async Task OrderBy_Contains_empty_list(bool async)
SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank"
FROM "Gears" AS "g"
-ORDER BY EXISTS (
- SELECT 1
+ORDER BY "g"."SquadId" IN (
+ SELECT "i"."value"
FROM json_each(@__ids_0) AS "i"
- WHERE "i"."value" = "g"."SquadId")
+)
""");
}
@@ -7976,10 +7976,10 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a
SELECT "t"."Id", "t"."GearNickName", "t"."GearSquadId", "t"."IssueDate", "t"."Note"
FROM "Tags" AS "t"
-WHERE EXISTS (
- SELECT 1
+WHERE "t"."Id" IN (
+ SELECT upper("i"."value") AS "value"
FROM json_each(@__ids_0) AS "i"
- WHERE upper("i"."value") = "t"."Id")
+)
""");
}
@@ -9463,8 +9463,8 @@ SELECT COALESCE(SUM(length("c"."Location")), 0)
FROM "Gears" AS "g2"
INNER JOIN "Squads" AS "s0" ON "g2"."SquadId" = "s0"."Id"
INNER JOIN "Cities" AS "c" ON "g2"."CityOfBirthName" = "c"."Name"
- WHERE EXISTS (
- SELECT 1
+ WHERE 'Marcus' IN (
+ SELECT "t0"."Nickname"
FROM (
SELECT "g3"."Nickname", "g3"."SquadId", "g3"."AssignedCityName", "g3"."CityOfBirthName", "g3"."Discriminator", "g3"."FullName", "g3"."HasSoulPatch", "g3"."LeaderNickname", "g3"."LeaderSquadId", "g3"."Rank"
FROM "Gears" AS "g3"
@@ -9472,11 +9472,11 @@ UNION ALL
SELECT "g4"."Nickname", "g4"."SquadId", "g4"."AssignedCityName", "g4"."CityOfBirthName", "g4"."Discriminator", "g4"."FullName", "g4"."HasSoulPatch", "g4"."LeaderNickname", "g4"."LeaderSquadId", "g4"."Rank"
FROM "Gears" AS "g4"
) AS "t0"
- WHERE "t0"."Nickname" = 'Marcus') AND ("s"."Name" = "s0"."Name" OR ("s"."Name" IS NULL AND "s0"."Name" IS NULL))) AS "SumOfLengths"
+ ) AND ("s"."Name" = "s0"."Name" OR ("s"."Name" IS NULL AND "s0"."Name" IS NULL))) AS "SumOfLengths"
FROM "Gears" AS "g"
INNER JOIN "Squads" AS "s" ON "g"."SquadId" = "s"."Id"
-WHERE EXISTS (
- SELECT 1
+WHERE 'Marcus' IN (
+ SELECT "t"."Nickname"
FROM (
SELECT "g0"."Nickname", "g0"."SquadId", "g0"."AssignedCityName", "g0"."CityOfBirthName", "g0"."Discriminator", "g0"."FullName", "g0"."HasSoulPatch", "g0"."LeaderNickname", "g0"."LeaderSquadId", "g0"."Rank"
FROM "Gears" AS "g0"
@@ -9484,7 +9484,7 @@ UNION ALL
SELECT "g1"."Nickname", "g1"."SquadId", "g1"."AssignedCityName", "g1"."CityOfBirthName", "g1"."Discriminator", "g1"."FullName", "g1"."HasSoulPatch", "g1"."LeaderNickname", "g1"."LeaderSquadId", "g1"."Rank"
FROM "Gears" AS "g1"
) AS "t"
- WHERE "t"."Nickname" = 'Marcus')
+)
GROUP BY "s"."Name"
""");
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs
index a24f9c503f7..f1d0e1adc6d 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/NullSemanticsQuerySqliteTest.cs
@@ -8,10 +8,108 @@ namespace Microsoft.EntityFrameworkCore.Query;
public class NullSemanticsQuerySqliteTest : NullSemanticsQueryTestBase
{
- public NullSemanticsQuerySqliteTest(NullSemanticsQuerySqliteFixture fixture)
+ // ReSharper disable once UnusedParameter.Local
+ public NullSemanticsQuerySqliteTest(NullSemanticsQuerySqliteFixture fixture, ITestOutputHelper testOutputHelper)
: base(fixture)
{
Fixture.TestSqlLoggerFactory.Clear();
+ //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
+ }
+
+ public override async Task Null_semantics_contains_non_nullable_item_with_non_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_non_nullable_item_with_non_nullable_subquery(async);
+
+ AssertSql(
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE "e"."StringA" IN (
+ SELECT "e0"."StringA"
+ FROM "Entities2" AS "e0"
+)
+""",
+ //
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE "e"."StringA" NOT IN (
+ SELECT "e0"."StringA"
+ FROM "Entities2" AS "e0"
+)
+""");
+ }
+
+ public override async Task Null_semantics_contains_nullable_item_with_non_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_nullable_item_with_non_nullable_subquery(async);
+
+ AssertSql(
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE "e"."NullableStringA" IN (
+ SELECT "e0"."StringA"
+ FROM "Entities2" AS "e0"
+)
+""",
+ //
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE "e"."NullableStringA" NOT IN (
+ SELECT "e0"."StringA"
+ FROM "Entities2" AS "e0"
+) OR "e"."NullableStringA" IS NULL
+""");
+ }
+
+ public override async Task Null_semantics_contains_non_nullable_item_with_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_non_nullable_item_with_nullable_subquery(async);
+
+ AssertSql(
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE "e"."StringA" IN (
+ SELECT "e0"."NullableStringA"
+ FROM "Entities2" AS "e0"
+)
+""",
+ //
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE NOT (COALESCE("e"."StringA" IN (
+ SELECT "e0"."NullableStringA"
+ FROM "Entities2" AS "e0"
+), 0))
+""");
+ }
+
+ public override async Task Null_semantics_contains_nullable_item_with_nullable_subquery(bool async)
+ {
+ await base.Null_semantics_contains_nullable_item_with_nullable_subquery(async);
+
+ AssertSql(
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE EXISTS (
+ SELECT 1
+ FROM "Entities2" AS "e0"
+ WHERE "e0"."NullableStringA" = "e"."NullableStringA" OR ("e0"."NullableStringA" IS NULL AND "e"."NullableStringA" IS NULL))
+""",
+ //
+"""
+SELECT "e"."Id"
+FROM "Entities1" AS "e"
+WHERE NOT EXISTS (
+ SELECT 1
+ FROM "Entities2" AS "e0"
+ WHERE "e0"."NullableStringA" = "e"."NullableStringA" OR ("e0"."NullableStringA" IS NULL AND "e"."NullableStringA" IS NULL))
+""");
}
public override async Task Bool_equal_nullable_bool_HasValue(bool async)
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
index 4d632724f6d..1fc9e9cf550 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
@@ -154,10 +154,10 @@ public override async Task Inline_collection_Contains_with_all_parameters(bool a
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."Id" IN (
+ SELECT "p0"."value"
FROM json_each(@__p_0) AS "p0"
- WHERE "p0"."value" = "p"."Id")
+)
""");
}
@@ -219,16 +219,16 @@ public override async Task Parameter_collection_of_ints_Contains(bool async)
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."Int" IN (
+ SELECT "i"."value"
FROM json_each(@__ints_0) AS "i"
- WHERE "i"."value" = "p"."Int")
+)
""");
}
- public override async Task Parameter_collection_of_nullable_ints_Contains(bool async)
+ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_int(async);
AssertSql(
"""
@@ -236,16 +236,16 @@ public override async Task Parameter_collection_of_nullable_ints_Contains(bool a
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."Int" IN (
+ SELECT "n"."value"
FROM json_each(@__nullableInts_0) AS "n"
- WHERE "n"."value" = "p"."NullableInt" OR ("n"."value" IS NULL AND "p"."NullableInt" IS NULL))
+)
""");
}
- public override async Task Parameter_collection_of_nullable_ints_Contains_null(bool async)
+ public override async Task Parameter_collection_of_nullable_ints_Contains_nullable_int(bool async)
{
- await base.Parameter_collection_of_nullable_ints_Contains_null(async);
+ await base.Parameter_collection_of_nullable_ints_Contains_nullable_int(async);
AssertSql(
"""
@@ -287,10 +287,10 @@ public override async Task Parameter_collection_of_DateTimes_Contains(bool async
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."DateTime" IN (
+ SELECT datetime("d"."value") AS "value"
FROM json_each(@__dateTimes_0) AS "d"
- WHERE datetime("d"."value") = "p"."DateTime")
+)
""");
}
@@ -304,10 +304,10 @@ public override async Task Parameter_collection_of_bools_Contains(bool async)
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."Bool" IN (
+ SELECT "b"."value"
FROM json_each(@__bools_0) AS "b"
- WHERE "b"."value" = "p"."Bool")
+)
""");
}
@@ -321,10 +321,10 @@ public override async Task Parameter_collection_of_enums_Contains(bool async)
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."Enum" IN (
+ SELECT "e"."value"
FROM json_each(@__enums_0) AS "e"
- WHERE "e"."value" = "p"."Enum")
+)
""");
}
@@ -336,10 +336,10 @@ public override async Task Parameter_collection_null_Contains(bool async)
"""
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE "p"."Int" IN (
+ SELECT "i"."value"
FROM json_each('[]') AS "i"
- WHERE "i"."value" = "p"."Int")
+)
""");
}
@@ -351,10 +351,10 @@ public override async Task Column_collection_of_ints_Contains(bool async)
"""
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE 10 IN (
+ SELECT "i"."value"
FROM json_each("p"."Ints") AS "i"
- WHERE "i"."value" = 10)
+)
""");
}
@@ -366,10 +366,10 @@ public override async Task Column_collection_of_nullable_ints_Contains(bool asyn
"""
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
+WHERE 10 IN (
+ SELECT "n"."value"
FROM json_each("p"."NullableInts") AS "n"
- WHERE "n"."value" = 10)
+)
""");
}
@@ -388,9 +388,9 @@ FROM json_each("p"."NullableInts") AS "n"
""");
}
- public override async Task Column_collection_of_bools_Contains(bool async)
+ public override async Task Column_collection_of_strings_contains_null(bool async)
{
- await base.Column_collection_of_bools_Contains(async);
+ await base.Column_collection_of_strings_contains_null(async);
AssertSql(
"""
@@ -398,8 +398,23 @@ public override async Task Column_collection_of_bools_Contains(bool async)
FROM "PrimitiveCollectionsEntity" AS "p"
WHERE EXISTS (
SELECT 1
+ FROM json_each("p"."Strings") AS "s"
+ WHERE "s"."value" IS NULL)
+""");
+ }
+
+ public override async Task Column_collection_of_bools_Contains(bool async)
+ {
+ await base.Column_collection_of_bools_Contains(async);
+
+ AssertSql(
+"""
+SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
+FROM "PrimitiveCollectionsEntity" AS "p"
+WHERE 1 IN (
+ SELECT "b"."value"
FROM json_each("p"."Bools") AS "b"
- WHERE "b"."value")
+)
""");
}
@@ -559,15 +574,12 @@ public override async Task Column_collection_Take(bool async)
"""
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT "i"."value", "i"."key"
- FROM json_each("p"."Ints") AS "i"
- ORDER BY "i"."key"
- LIMIT 2
- ) AS "t"
- WHERE "t"."value" = 11)
+WHERE 11 IN (
+ SELECT "i"."value"
+ FROM json_each("p"."Ints") AS "i"
+ ORDER BY "i"."key"
+ LIMIT 2
+)
""");
}
@@ -579,15 +591,12 @@ public override async Task Column_collection_Skip_Take(bool async)
"""
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."String", "p"."Strings"
FROM "PrimitiveCollectionsEntity" AS "p"
-WHERE EXISTS (
- SELECT 1
- FROM (
- SELECT "i"."value", "i"."key"
- FROM json_each("p"."Ints") AS "i"
- ORDER BY "i"."key"
- LIMIT 2 OFFSET 1
- ) AS "t"
- WHERE "t"."value" = 11)
+WHERE 11 IN (
+ SELECT "i"."value"
+ FROM json_each("p"."Ints") AS "i"
+ ORDER BY "i"."key"
+ LIMIT 2 OFFSET 1
+)
""");
}