diff --git a/NuGet.config b/NuGet.config index d1a8a417e43..eddc149aad5 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,6 +2,7 @@ + diff --git a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs index ff816843742..bdd907f01b2 100644 --- a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs @@ -1610,6 +1610,46 @@ public static void SetContainerColumnName(this IMutableEntityType entityType, st ? columnName : (entityType.FindOwnership()?.PrincipalEntityType.GetContainerColumnName()); + /// + /// Sets the column type to use for the container column to which the entity type is mapped. + /// + /// The entity type. + /// The database column type. + public static void SetContainerColumnType(this IMutableEntityType entityType, string? columnType) + => entityType.SetOrRemoveAnnotation(RelationalAnnotationNames.ContainerColumnType, columnType); + + /// + /// Sets the column type to use for the container column to which the entity type is mapped. + /// + /// The entity type. + /// The database column type. + /// Indicates whether the configuration was specified using a data annotation. + /// The configured value. + public static string? SetContainerColumnType( + this IConventionEntityType entityType, + string? columnType, + bool fromDataAnnotation = false) + => (string?)entityType.SetAnnotation(RelationalAnnotationNames.ContainerColumnType, columnType, fromDataAnnotation)?.Value; + + /// + /// Gets the for the container column type. + /// + /// The entity type. + /// The . + public static ConfigurationSource? GetContainerColumnTypeConfigurationSource(this IConventionEntityType entityType) + => entityType.FindAnnotation(RelationalAnnotationNames.ContainerColumnType) + ?.GetConfigurationSource(); + + /// + /// Gets the column type to use for the container column to which the entity type is mapped. + /// + /// The entity type. + /// The database column type. + public static string? GetContainerColumnType(this IReadOnlyEntityType entityType) + => entityType.FindAnnotation(RelationalAnnotationNames.ContainerColumnType)?.Value is string columnType + ? columnType + : (entityType.FindOwnership()?.PrincipalEntityType.GetContainerColumnType()); + /// /// Sets the type mapping for the container column to which the entity type is mapped. /// diff --git a/src/EFCore.Relational/Extensions/RelationalOwnedNavigationBuilderExtensions.cs b/src/EFCore.Relational/Extensions/RelationalOwnedNavigationBuilderExtensions.cs index 0f0329748a5..158c3993cfc 100644 --- a/src/EFCore.Relational/Extensions/RelationalOwnedNavigationBuilderExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalOwnedNavigationBuilderExtensions.cs @@ -23,12 +23,7 @@ public static class RelationalOwnedNavigationBuilderExtensions /// The builder for the owned navigation being configured. /// The same builder instance so that multiple calls can be chained. public static OwnedNavigationBuilder ToJson(this OwnedNavigationBuilder builder) - { - var navigationName = builder.Metadata.GetNavigation(pointsToPrincipal: false)!.Name; - builder.ToJson(navigationName); - - return builder; - } + => builder.ToJson(builder.Metadata.GetNavigation(pointsToPrincipal: false)!.Name); /// /// Configures a relationship where this entity type and the entities that it owns are mapped to a JSON column in the database. @@ -45,12 +40,7 @@ public static OwnedNavigationBuilder ToJson builder) where TOwnerEntity : class where TDependentEntity : class - { - var navigationName = builder.Metadata.GetNavigation(pointsToPrincipal: false)!.Name; - builder.ToJson(navigationName); - - return builder; - } + => (OwnedNavigationBuilder)((OwnedNavigationBuilder)builder).ToJson(); /// /// Configures a relationship where this entity type and the entities that it owns are mapped to a JSON column in the database. @@ -68,11 +58,7 @@ public static OwnedNavigationBuilder ToJson builder.ToJson(jsonColumnName, null); /// /// Configures a relationship where this entity type and the entities that it owns are mapped to a JSON column in the database. @@ -88,8 +74,47 @@ public static OwnedNavigationBuilder ToJson builder.ToJson(jsonColumnName, null); + + /// + /// Configures a relationship where this entity type and the entities that it owns are mapped to a JSON column in the database. + /// + /// + /// This method should only be specified for the outer-most owned entity in the given ownership structure. + /// All entities owned by this will be automatically mapped to the same JSON column. + /// The ownerships must still be explicitly defined. + /// + /// The builder for the owned navigation being configured. + /// JSON column name to use. + /// The database type for the JSON column, or to use the database default. + /// The same builder instance so that multiple calls can be chained. + public static OwnedNavigationBuilder ToJson( + this OwnedNavigationBuilder builder, + string? jsonColumnName, + string? jsonColumnType) + where TOwnerEntity : class + where TDependentEntity : class + => (OwnedNavigationBuilder)((OwnedNavigationBuilder)builder).ToJson(jsonColumnName, jsonColumnType); + + /// + /// Configures a relationship where this entity type and the entities that it owns are mapped to a JSON column in the database. + /// + /// + /// This method should only be specified for the outer-most owned entity in the given ownership structure. + /// All entities owned by this will be automatically mapped to the same JSON column. + /// The ownerships must still be explicitly defined. + /// + /// The builder for the owned navigation being configured. + /// JSON column name to use. + /// The database type for the JSON column, or to use the database default. + /// The same builder instance so that multiple calls can be chained. + public static OwnedNavigationBuilder ToJson( + this OwnedNavigationBuilder builder, + string? jsonColumnName, + string? jsonColumnType) { builder.OwnedEntityType.SetContainerColumnName(jsonColumnName); + builder.OwnedEntityType.SetContainerColumnType(jsonColumnType); return builder; } diff --git a/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs b/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs index 08e551a6ebc..0963c7b1db6 100644 --- a/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs @@ -368,6 +368,17 @@ public static bool IsMappedToJson(this IReadOnlyTypeBase typeBase) ? entityType.GetContainerColumnName() : ((IReadOnlyComplexType)typeBase).GetContainerColumnName(); + + /// + /// Gets the column type to use for the container column to which the type is mapped. + /// + /// The type. + /// The database column type. + public static string? GetContainerColumnType(this IReadOnlyTypeBase typeBase) + => typeBase is IReadOnlyEntityType entityType + ? entityType.GetContainerColumnType() + : null; + /// /// Gets the value of JSON property name used for the given entity mapped to a JSON column. /// diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs index 637be020b0e..3bfa99bd9c3 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs @@ -286,12 +286,14 @@ private static void AddDefaultMappings( includesDerivedTypes: entityType.GetDirectlyDerivedTypes().Any() ? !isTpc && mappedType == entityType : null); + var containerColumnName = mappedType.GetContainerColumnName(); + var containerColumnType = mappedType.GetContainerColumnType(); if (!string.IsNullOrEmpty(containerColumnName)) { CreateContainerColumn( - defaultTable, containerColumnName, mappedType, relationalTypeMappingSource, - static (c, t, m) => new JsonColumnBase(c, m.StoreType, t, m)); + defaultTable, containerColumnName, containerColumnType, mappedType, relationalTypeMappingSource, + static (colName, colType, table, mapping) => new JsonColumnBase(colName, colType ?? mapping.StoreType, table, mapping)); } else { @@ -492,11 +494,12 @@ private static void CreateTableMapping( }; var containerColumnName = mappedType.GetContainerColumnName(); + var containerColumnType = mappedType.GetContainerColumnType(); if (!string.IsNullOrEmpty(containerColumnName)) { CreateContainerColumn( - table, containerColumnName, (IEntityType)mappedType, relationalTypeMappingSource, - static (c, t, m) => new JsonColumn(c, m.StoreType, (Table)t, m)); + table, containerColumnName, containerColumnType, (IEntityType)mappedType, relationalTypeMappingSource, + static (colName, colType, table, mapping) => new JsonColumn(colName, colType ?? mapping.StoreType, (Table)table, mapping)); } else { @@ -567,9 +570,10 @@ private static void CreateTableMapping( private static void CreateContainerColumn( TableBase tableBase, string containerColumnName, + string? containerColumnType, IEntityType mappedType, IRelationalTypeMappingSource relationalTypeMappingSource, - Func> createColumn) + Func> createColumn) where TColumnMappingBase : class, IColumnMappingBase { var ownership = mappedType.GetForeignKeys().Single(fk => fk.IsOwnership); @@ -577,8 +581,8 @@ private static void CreateContainerColumn( { Check.DebugAssert(tableBase.FindColumn(containerColumnName) == null, $"Table does not have column '{containerColumnName}'."); - var jsonColumnTypeMapping = relationalTypeMappingSource.FindMapping(typeof(JsonElement), mappedType.Model)!; - var jsonColumn = createColumn(containerColumnName, tableBase, jsonColumnTypeMapping); + var jsonColumnTypeMapping = relationalTypeMappingSource.FindMapping(typeof(JsonElement), storeTypeName: containerColumnType)!; + var jsonColumn = createColumn(containerColumnName, containerColumnType, tableBase, jsonColumnTypeMapping); tableBase.Columns.Add(containerColumnName, jsonColumn); jsonColumn.IsNullable = !ownership.IsRequiredDependent || !ownership.IsUnique; @@ -684,11 +688,12 @@ private static void CreateViewMapping( }; var containerColumnName = mappedType.GetContainerColumnName(); + var containerColumnType = mappedType.GetContainerColumnType(); if (!string.IsNullOrEmpty(containerColumnName)) { CreateContainerColumn( - view, containerColumnName, mappedType, relationalTypeMappingSource, - static (c, t, m) => new JsonViewColumn(c, m.StoreType, (View)t, m)); + view, containerColumnName, containerColumnType, mappedType, relationalTypeMappingSource, + static (colName, colType, table, mapping) => new JsonViewColumn(colName, colType ?? mapping.StoreType, (View)table, mapping)); } else { diff --git a/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs b/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs index 6041736eca8..e0337d77f04 100644 --- a/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs +++ b/src/EFCore.Relational/Metadata/RelationalAnnotationNames.cs @@ -324,6 +324,11 @@ public static class RelationalAnnotationNames /// public const string ContainerColumnName = Prefix + "ContainerColumnName"; + /// + /// The column type for the container column to which the object is mapped. + /// + public const string ContainerColumnType = Prefix + nameof(ContainerColumnType); + /// /// The name for the annotation specifying container column type mapping. /// diff --git a/src/EFCore.SqlServer/EFCore.SqlServer.csproj b/src/EFCore.SqlServer/EFCore.SqlServer.csproj index 2709d8d7fcc..8b94478d2dc 100644 --- a/src/EFCore.SqlServer/EFCore.SqlServer.csproj +++ b/src/EFCore.SqlServer/EFCore.SqlServer.csproj @@ -41,6 +41,7 @@ + @@ -49,7 +50,7 @@ - + diff --git a/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerOpenJsonExpression.cs b/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerOpenJsonExpression.cs index 09c39858a56..11f0b64226a 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerOpenJsonExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerOpenJsonExpression.cs @@ -321,4 +321,14 @@ public readonly record struct ColumnInfo( RelationalTypeMapping TypeMapping, IReadOnlyList? Path = null, bool AsJson = false); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual SqlServerOpenJsonExpression Update(SqlExpression sqlExpression) + => new(Alias, sqlExpression, Path, ColumnInfos); + } diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs index 6e5693a4670..337b21bbec3 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs @@ -475,7 +475,7 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp return jsonScalarExpression; } - if (jsonScalarExpression.TypeMapping is SqlServerJsonTypeMapping + if (jsonScalarExpression.TypeMapping is SqlServerJsonElementTypeMapping || jsonScalarExpression.TypeMapping?.ElementTypeMapping is not null) { Sql.Append("JSON_QUERY("); @@ -494,7 +494,7 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp GenerateJsonPath(jsonScalarExpression.Path); Sql.Append(")"); - if (jsonScalarExpression.TypeMapping is not SqlServerJsonTypeMapping and not StringTypeMapping) + if (jsonScalarExpression.TypeMapping is not SqlServerJsonElementTypeMapping and not StringTypeMapping) { Sql.Append(" AS "); Sql.Append(jsonScalarExpression.TypeMapping!.StoreType); diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerTypeMappingPostprocessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerTypeMappingPostprocessor.cs index 1aa6607bd87..3cfad0135ab 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerTypeMappingPostprocessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerTypeMappingPostprocessor.cs @@ -43,8 +43,7 @@ protected override Expression VisitExtension(Expression expression) => expression switch { SqlServerOpenJsonExpression openJsonExpression - when TryGetInferredTypeMapping(openJsonExpression.Alias, "value", out var typeMapping) - => ApplyTypeMappingsOnOpenJsonExpression(openJsonExpression, new[] { typeMapping }), + => ApplyTypeMappingsOnOpenJsonExpression(openJsonExpression), _ => base.VisitExtension(expression) }; @@ -55,12 +54,21 @@ when TryGetInferredTypeMapping(openJsonExpression.Alias, "value", out var typeMa /// 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 virtual SqlServerOpenJsonExpression ApplyTypeMappingsOnOpenJsonExpression( - SqlServerOpenJsonExpression openJsonExpression, - IReadOnlyList typeMappings) + protected virtual SqlServerOpenJsonExpression ApplyTypeMappingsOnOpenJsonExpression(SqlServerOpenJsonExpression openJsonExpression) { - Check.DebugAssert(typeMappings.Count == 1, "typeMappings.Count == 1"); - var elementTypeMapping = typeMappings[0]; + if (openJsonExpression is { JsonExpression.TypeMapping: SqlServerStringTypeMapping { StoreType: "json" } } or + { JsonExpression.TypeMapping: SqlServerJsonElementTypeMapping { StoreType: "json" } }) + { + openJsonExpression = openJsonExpression.Update( + new SqlUnaryExpression( + ExpressionType.Convert, (SqlExpression)Visit(openJsonExpression.JsonExpression), typeof(string), + _typeMappingSource.FindMapping(typeof(string))!)); + } + + if (!TryGetInferredTypeMapping(openJsonExpression.Alias, "value", out var elementTypeMapping)) + { + return openJsonExpression; + } // Constant queryables are translated to VALUES, no need for JSON. // Column queryables have their type mapping from the model, so we don't ever need to apply an inferred mapping on them. diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerJsonTypeMapping.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerJsonElementTypeMapping.cs similarity index 76% rename from src/EFCore.SqlServer/Storage/Internal/SqlServerJsonTypeMapping.cs rename to src/EFCore.SqlServer/Storage/Internal/SqlServerJsonElementTypeMapping.cs index 8f6e7923d3a..461783c45f8 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerJsonTypeMapping.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerJsonElementTypeMapping.cs @@ -1,8 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Data; using System.Text; using System.Text.Json; +using Microsoft.Data.SqlClient; namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; @@ -12,7 +14,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// -public class SqlServerJsonTypeMapping : JsonTypeMapping +public class SqlServerJsonElementTypeMapping : JsonTypeMapping { private static readonly MethodInfo GetStringMethod = typeof(DbDataReader).GetRuntimeMethod(nameof(DbDataReader.GetString), [typeof(int)])!; @@ -32,7 +34,7 @@ private static readonly ConstructorInfo MemoryStreamConstructor /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public static SqlServerJsonTypeMapping Default { get; } = new("nvarchar(max)"); + public static SqlServerJsonElementTypeMapping Default { get; } = new("nvarchar(max)"); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -40,7 +42,15 @@ private static readonly ConstructorInfo MemoryStreamConstructor /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public SqlServerJsonTypeMapping(string storeType) + public static SqlServerJsonElementTypeMapping JsonTypeDefault { get; } = new("json"); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public SqlServerJsonElementTypeMapping(string storeType) : base(storeType, typeof(JsonElement), System.Data.DbType.String) { } @@ -74,7 +84,7 @@ public override Expression CustomizeDataReaderExpression(Expression expression) /// 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 SqlServerJsonTypeMapping(RelationalTypeMappingParameters parameters) + protected SqlServerJsonElementTypeMapping(RelationalTypeMappingParameters parameters) : base(parameters) { } @@ -104,5 +114,22 @@ protected override string GenerateNonNullSqlLiteral(object value) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters) - => new SqlServerJsonTypeMapping(parameters); + => new SqlServerJsonElementTypeMapping(parameters); + + /// + /// 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 void ConfigureParameter(DbParameter parameter) + { + if ("json".Equals(StoreType, StringComparison.OrdinalIgnoreCase) + && parameter is SqlParameter sqlParameter) // To avoid crashing wrapping providers + { + sqlParameter.SqlDbType = ((SqlDbType)35); + } + + base.ConfigureParameter(parameter); + } } diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerStringTypeMapping.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerStringTypeMapping.cs index 7d3d6f724e0..c286786d787 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerStringTypeMapping.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerStringTypeMapping.cs @@ -34,6 +34,23 @@ public class SqlServerStringTypeMapping : StringTypeMapping /// public static new SqlServerStringTypeMapping Default { get; } = new(); + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public static SqlServerStringTypeMapping JsonTypeDefault { get; } = new("json", sqlDbType: (SqlDbType)35); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public static SqlServerStringTypeMapping UnicodeDefault { get; } = new( + "nvarchar(max)", unicode: true, storeTypePostfix: StoreTypePostfix.None); + /// /// 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 @@ -68,7 +85,9 @@ public SqlServerStringTypeMapping( private static string GetDefaultStoreName(bool unicode, bool fixedLength) => unicode ? fixedLength ? "nchar" : "nvarchar" - : fixedLength ? "char" : "varchar"; + : fixedLength + ? "char" + : "varchar"; private static DbType? GetDbType(bool unicode, bool fixedLength) => unicode @@ -138,10 +157,13 @@ protected override void ConfigureParameter(DbParameter parameter) var value = parameter.Value; var length = (value as string)?.Length; - if (_sqlDbType.HasValue + var sqlDbType = _sqlDbType + ?? (StoreType == "json" ? (SqlDbType)35 : null); + + if (sqlDbType.HasValue && parameter is SqlParameter sqlParameter) // To avoid crashing wrapping providers { - sqlParameter.SqlDbType = _sqlDbType.Value; + sqlParameter.SqlDbType = sqlDbType.Value; } if ((value == null diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs index be70a79a7af..a0de9806e61 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs @@ -141,8 +141,7 @@ static SqlServerTypeMappingSource() { typeof(float), SqlServerFloatTypeMapping.Default }, { typeof(decimal), SqlServerDecimalTypeMapping.Default }, { typeof(TimeOnly), SqlServerTimeOnlyTypeMapping.Default }, - { typeof(TimeSpan), SqlServerTimeSpanTypeMapping.Default }, - { typeof(JsonElement), SqlServerJsonTypeMapping.Default } + { typeof(TimeSpan), SqlServerTimeSpanTypeMapping.Default } }; _clrNoFacetTypeMappings @@ -180,6 +179,7 @@ static SqlServerTypeMappingSource() { "float", [SqlServerDoubleTypeMapping.Default] }, { "image", [ImageBinary] }, { "int", [IntTypeMapping.Default] }, + { "json", [SqlServerStringTypeMapping.JsonTypeDefault] }, { "money", [Money] }, { "national char varying", [VariableLengthUnicodeString] }, { "national char varying(max)", [VariableLengthMaxUnicodeString] }, @@ -239,6 +239,13 @@ public SqlServerTypeMappingSource( var clrType = mappingInfo.ClrType; var storeTypeName = mappingInfo.StoreTypeName; + if (clrType == typeof(JsonElement)) + { + return "json".Equals(storeTypeName, StringComparison.OrdinalIgnoreCase) + ? SqlServerJsonElementTypeMapping.JsonTypeDefault + : SqlServerJsonElementTypeMapping.Default; + } + if (storeTypeName != null) { var storeTypeNameBase = mappingInfo.StoreTypeNameBase; @@ -310,6 +317,11 @@ public SqlServerTypeMappingSource( if (clrType == typeof(string)) { + if (storeTypeName == "json") + { + return SqlServerStringTypeMapping.JsonTypeDefault; + } + var isAnsi = mappingInfo.IsUnicode == false; var isFixedLength = mappingInfo.IsFixedLength == true; var maxSize = isAnsi ? 8000 : 4000; diff --git a/src/EFCore.SqlServer/Update/Internal/SqlServerModificationCommand.cs b/src/EFCore.SqlServer/Update/Internal/SqlServerModificationCommand.cs index 7f46d58d144..c364383fdc4 100644 --- a/src/EFCore.SqlServer/Update/Internal/SqlServerModificationCommand.cs +++ b/src/EFCore.SqlServer/Update/Internal/SqlServerModificationCommand.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; + namespace Microsoft.EntityFrameworkCore.SqlServer.Update.Internal; /// @@ -32,4 +34,59 @@ public SqlServerModificationCommand(in NonTrackedModificationCommandParameters m : base(modificationCommandParameters) { } + + /// + /// 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 void ProcessSinglePropertyJsonUpdate(ref ColumnModificationParameters parameters) + { + var property = parameters.Property!; + var mapping = property.GetRelationalTypeMapping(); + var propertyProviderClrType = (mapping.Converter?.ProviderClrType ?? property.ClrType).UnwrapNullableType(); + var value = parameters.Value; + + // JSON-compatible non-string values (bool, numeric, null) are sent directly as non-string parameters. + if (value == null + || propertyProviderClrType == typeof(bool) + || propertyProviderClrType.IsNumeric()) + { + parameters = parameters with { Value = value, TypeMapping = mapping }; + } + else + { + // Everything else must go as either a string parameter or a json parameter, depending on whether the json type + // is being used or not. To determine this, we get the JSON value and check if it is a string or some other + // type of JSON object. + var jsonValueReaderWriter = mapping.JsonValueReaderWriter; + if (jsonValueReaderWriter != null) + { + var stringValue = jsonValueReaderWriter.ToJsonString(value); + if (!stringValue.StartsWith('\"')) + { + // This is actual JSON, so send with the original type mapping, which may indicate the column type is JSON. + parameters = parameters with { Value = stringValue }; + + return; + } + + // Otherwise remove the quotes and send the value as a string. + value = stringValue[1..^1]; + } + else if (mapping.Converter != null) + { + value = mapping.Converter.ConvertToProvider(value); + } + + parameters = parameters with + { + Value = value, + TypeMapping = parameters.TypeMapping is SqlServerJsonElementTypeMapping + ? SqlServerStringTypeMapping.UnicodeDefault + : parameters.TypeMapping + }; + } + } } diff --git a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryTestBase.cs index d0467f17ecc..758b378007a 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryTestBase.cs @@ -16,10 +16,13 @@ protected override string StoreName [MemberData(nameof(IsAsyncData))] public virtual async Task Contains_on_nested_collection_with_init_only_navigation(bool async) { - var contextFactory = await InitializeAsync(seed: Seed32310); + var contextFactory = await InitializeAsync( + onModelCreating: b => b.Entity().OwnsOne(e => e.Visits).ToJson("Visits", JsonColumnType), + seed: Seed32310); + await using var context = contextFactory.CreateContext(); - var query = context.Pubs + var query = context.Set() .Where(u => u.Visits.DaysVisited.Contains(new DateOnly(2023, 1, 1))); var result = async @@ -30,7 +33,7 @@ public virtual async Task Contains_on_nested_collection_with_init_only_navigatio Assert.Equal(new DateOnly(2023, 1, 1), result.Visits.DaysVisited.Single()); } - protected virtual async Task Seed32310(MyContext32310 context) + protected virtual async Task Seed32310(DbContext context) { var user = new Pub32310 { Name = "FBI", Visits = new Visits32310 { LocationTag = "tag", DaysVisited = [new(2023, 1, 1)] } }; @@ -38,15 +41,6 @@ protected virtual async Task Seed32310(MyContext32310 context) await context.SaveChangesAsync(); } - protected class MyContext32310(DbContextOptions options) : DbContext(options) - { - public DbSet Pubs - => Set(); - - protected override void OnModelCreating(ModelBuilder modelBuilder) - => modelBuilder.Entity(b => { b.OwnsOne(e => e.Visits).ToJson(); }); - } - public class Pub32310 { public int Id { get; set; } @@ -68,12 +62,11 @@ public class Visits32310 [MemberData(nameof(IsAsyncData))] public virtual async Task Optional_json_properties_materialized_as_null_when_the_element_in_json_is_not_present(bool async) { - var contextFactory = await InitializeAsync( - seed: Seed29219); + var contextFactory = await InitializeAsync(BuildModel29219, seed: Seed29219); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.Where(x => x.Id == 3); + var query = context.Set().Where(x => x.Id == 3); var result = async ? await query.SingleAsync() @@ -89,12 +82,11 @@ public virtual async Task Optional_json_properties_materialized_as_null_when_the [MemberData(nameof(IsAsyncData))] public virtual async Task Can_project_nullable_json_property_when_the_element_in_json_is_not_present(bool async) { - var contextFactory = await InitializeAsync( - seed: Seed29219); + var contextFactory = await InitializeAsync(BuildModel29219, seed: Seed29219); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.OrderBy(x => x.Id).Select(x => x.Reference.NullableScalar); + var query = context.Set().OrderBy(x => x.Id).Select(x => x.Reference.NullableScalar); var result = async ? await query.ToListAsync() @@ -107,19 +99,17 @@ public virtual async Task Can_project_nullable_json_property_when_the_element_in } } - protected abstract Task Seed29219(MyContext29219 ctx); + protected void BuildModel29219(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.ToTable("Entities"); + b.Property(x => x.Id).ValueGeneratedNever(); + b.OwnsOne(x => x.Reference).ToJson("Reference", JsonColumnType); + b.OwnsMany(x => x.Collection).ToJson("Collection", JsonColumnType); + }); - protected class MyContext29219(DbContextOptions options) : DbContext(options) - { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson(); - modelBuilder.Entity().OwnsMany(x => x.Collection).ToJson(); - } - } + protected abstract Task Seed29219(DbContext ctx); public class MyEntity29219 { @@ -138,28 +128,24 @@ public class MyJsonEntity29219 #region 30028 - protected abstract Task Seed30028(MyContext30028 ctx); - - protected class MyContext30028(DbContextOptions options) : DbContext(options) - { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - => modelBuilder.Entity( - b => - { - b.Property(x => x.Id).ValueGeneratedNever(); - b.OwnsOne( - x => x.Json, nb => - { - nb.ToJson(); - nb.OwnsMany(x => x.Collection, nnb => nnb.OwnsOne(x => x.Nested)); - nb.OwnsOne(x => x.OptionalReference, nnb => nnb.OwnsOne(x => x.Nested)); - nb.OwnsOne(x => x.RequiredReference, nnb => nnb.OwnsOne(x => x.Nested)); - nb.Navigation(x => x.RequiredReference).IsRequired(); - }); - }); - } + protected abstract Task Seed30028(DbContext ctx); + + protected virtual void BuildModel30028(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.Property(x => x.Id).ValueGeneratedNever(); + b.ToTable("Entities"); + b.OwnsOne( + x => x.Json, nb => + { + nb.ToJson("Json", JsonColumnType); + nb.OwnsMany(x => x.Collection, nnb => nnb.OwnsOne(x => x.Nested)); + nb.OwnsOne(x => x.OptionalReference, nnb => nnb.OwnsOne(x => x.Nested)); + nb.OwnsOne(x => x.RequiredReference, nnb => nnb.OwnsOne(x => x.Nested)); + nb.Navigation(x => x.RequiredReference).IsRequired(); + }); + }); public class MyEntity30028 { @@ -190,10 +176,10 @@ public class MyJsonLeafEntity30028 [MemberData(nameof(IsAsyncData))] public virtual async Task Accessing_missing_navigation_works(bool async) { - var contextFactory = await InitializeAsync(seed: Seed30028); + var contextFactory = await InitializeAsync(BuildModel30028, seed: Seed30028); using (var context = contextFactory.CreateContext()) { - var result = context.Entities.OrderBy(x => x.Id).ToList(); + var result = context.Set().OrderBy(x => x.Id).ToList(); Assert.Equal(4, result.Count); Assert.NotNull(result[0].Json.Collection); Assert.NotNull(result[0].Json.OptionalReference); @@ -213,14 +199,14 @@ public virtual async Task Accessing_missing_navigation_works(bool async) } } - [ConditionalTheory] + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] [MemberData(nameof(IsAsyncData))] public virtual async Task Missing_navigation_works_with_deduplication(bool async) { - var contextFactory = await InitializeAsync(seed: Seed30028); + var contextFactory = await InitializeAsync(BuildModel30028, seed: Seed30028); using (var context = contextFactory.CreateContext()) { - var result = context.Entities.OrderBy(x => x.Id).Select( + var result = context.Set().OrderBy(x => x.Id).Select( x => new { x, @@ -266,108 +252,101 @@ public virtual async Task Missing_navigation_works_with_deduplication(bool async [ConditionalFact] public virtual async Task Project_json_with_no_properties() { - var contextFactory = await InitializeAsync(seed: Seed30028); + var contextFactory = await InitializeAsync(BuildModel32939, seed: Seed32939); using var context = contextFactory.CreateContext(); - context.Entities.ToList(); + context.Set().ToList(); } - protected Task Seed30028(Context32939 ctx) + protected Task Seed32939(DbContext ctx) { - var entity = new Context32939.Entity32939 + var entity = new Entity32939 { - Empty = new Context32939.JsonEmpty32939(), - FieldOnly = new Context32939.JsonFieldOnly32939() + Empty = new JsonEmpty32939(), + FieldOnly = new JsonFieldOnly32939() }; - ctx.Entities.Add(entity); + ctx.Add(entity); return ctx.SaveChangesAsync(); } - protected class Context32939(DbContextOptions options) : DbContext(options) + protected virtual void BuildModel32939(ModelBuilder modelBuilder) { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne(x => x.Empty, b => b.ToJson()); - modelBuilder.Entity().OwnsOne(x => x.FieldOnly, b => b.ToJson()); - } + modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); + modelBuilder.Entity().OwnsOne(x => x.Empty, b => b.ToJson("Empty", JsonColumnType)); + modelBuilder.Entity().OwnsOne(x => x.FieldOnly, b => b.ToJson("FieldOnly", JsonColumnType)); + } - public class Entity32939 - { - public int Id { get; set; } - public JsonEmpty32939 Empty { get; set; } - public JsonFieldOnly32939 FieldOnly { get; set; } + public class Entity32939 + { + public int Id { get; set; } + public JsonEmpty32939 Empty { get; set; } + public JsonFieldOnly32939 FieldOnly { get; set; } - } + } - public class JsonEmpty32939 - { - } + public class JsonEmpty32939 + { + } - public class JsonFieldOnly32939 - { - public int Field; - } + public class JsonFieldOnly32939 + { + public int Field; } #endregion #region 33046 - protected abstract Task Seed33046(Context33046 ctx); + protected abstract Task Seed33046(DbContext ctx); [ConditionalFact] public virtual async Task Query_with_nested_json_collection_mapped_to_private_field_via_IReadOnlyList() { - var contextFactory = await InitializeAsync(seed: Seed33046); + var contextFactory = await InitializeAsync(BuildModel33046, seed: Seed33046); using var context = contextFactory.CreateContext(); - var query = context.Reviews.ToList(); + var query = context.Set().ToList(); Assert.Equal(1, query.Count); } - protected class Context33046(DbContextOptions options) : DbContext(options) - { - public DbSet Reviews { get; set; } + protected virtual void BuildModel33046(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.ToTable("Reviews"); + b.Property(x => x.Id).ValueGeneratedNever(); + b.OwnsMany( + x => x.Rounds, ownedBuilder => + { + ownedBuilder.ToJson("Rounds", JsonColumnType); + ownedBuilder.OwnsMany(r => r.SubRounds); + }); + }); - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsMany( - x => x.Rounds, ownedBuilder => - { - ownedBuilder.ToJson(); - ownedBuilder.OwnsMany(r => r.SubRounds); - }); - } - - public class Review - { - public int Id { get; set; } + public class Review + { + public int Id { get; set; } #pragma warning disable IDE0044 // Add readonly modifier - private List _rounds = []; + private List _rounds = []; #pragma warning restore IDE0044 // Add readonly modifier - public IReadOnlyList Rounds - => _rounds.AsReadOnly(); - } + public IReadOnlyList Rounds + => _rounds.AsReadOnly(); + } - public class ReviewRound - { - public int RoundNumber { get; set; } + public class ReviewRound + { + public int RoundNumber { get; set; } #pragma warning disable IDE0044 // Add readonly modifier - private List _subRounds = []; + private List _subRounds = []; #pragma warning restore IDE0044 // Add readonly modifier - public IReadOnlyList SubRounds - => _subRounds.AsReadOnly(); - } + public IReadOnlyList SubRounds + => _subRounds.AsReadOnly(); + } - public class SubRound - { - public int SubRoundNumber { get; set; } - } + public class SubRound + { + public int SubRoundNumber { get; set; } } #endregion @@ -378,12 +357,11 @@ public class SubRound [MemberData(nameof(IsAsyncData))] public virtual async Task Project_json_array_of_primitives_on_reference(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedArrayOfPrimitives); + var contextFactory = await InitializeAsync(BuildModelArrayOfPrimitives, seed: SeedArrayOfPrimitives); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.OrderBy(x => x.Id).Select(x => new { x.Reference.IntArray, x.Reference.ListOfString }); + var query = context.Set().OrderBy(x => x.Id).Select(x => new { x.Reference.IntArray, x.Reference.ListOfString }); var result = async ? await query.ToListAsync() @@ -401,12 +379,11 @@ public virtual async Task Project_json_array_of_primitives_on_reference(bool asy [MemberData(nameof(IsAsyncData))] public virtual async Task Project_json_array_of_primitives_on_collection(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedArrayOfPrimitives); + var contextFactory = await InitializeAsync(BuildModelArrayOfPrimitives, seed: SeedArrayOfPrimitives); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.OrderBy(x => x.Id).Select(x => new { x.Collection[0].IntArray, x.Collection[1].ListOfString }); + var query = context.Set().OrderBy(x => x.Id).Select(x => new { x.Collection[0].IntArray, x.Collection[1].ListOfString }); var result = async ? await query.ToListAsync() @@ -424,12 +401,11 @@ public virtual async Task Project_json_array_of_primitives_on_collection(bool as [MemberData(nameof(IsAsyncData))] public virtual async Task Project_element_of_json_array_of_primitives(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedArrayOfPrimitives); + var contextFactory = await InitializeAsync(BuildModelArrayOfPrimitives, seed: SeedArrayOfPrimitives); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.OrderBy(x => x.Id).Select( + var query = context.Set().OrderBy(x => x.Id).Select( x => new { ArrayElement = x.Reference.IntArray[0], ListElement = x.Reference.ListOfString[1] }); var result = async @@ -442,12 +418,11 @@ public virtual async Task Project_element_of_json_array_of_primitives(bool async [MemberData(nameof(IsAsyncData))] public virtual async Task Predicate_based_on_element_of_json_array_of_primitives1(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedArrayOfPrimitives); + var contextFactory = await InitializeAsync(BuildModelArrayOfPrimitives, seed: SeedArrayOfPrimitives); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.Where(x => x.Reference.IntArray[0] == 1); + var query = context.Set().Where(x => x.Reference.IntArray[0] == 1); var result = async ? await query.ToListAsync() @@ -462,12 +437,11 @@ public virtual async Task Predicate_based_on_element_of_json_array_of_primitives [MemberData(nameof(IsAsyncData))] public virtual async Task Predicate_based_on_element_of_json_array_of_primitives2(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedArrayOfPrimitives); + var contextFactory = await InitializeAsync(BuildModelArrayOfPrimitives, seed: SeedArrayOfPrimitives); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.Where(x => x.Reference.ListOfString[1] == "Bar"); + var query = context.Set().Where(x => x.Reference.ListOfString[1] == "Bar"); var result = async ? await query.ToListAsync() @@ -482,12 +456,11 @@ public virtual async Task Predicate_based_on_element_of_json_array_of_primitives [MemberData(nameof(IsAsyncData))] public virtual async Task Predicate_based_on_element_of_json_array_of_primitives3(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedArrayOfPrimitives); + var contextFactory = await InitializeAsync(BuildModelArrayOfPrimitives, seed: SeedArrayOfPrimitives); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.Where( + var query = context.Set().Where( x => x.Reference.IntArray.AsQueryable().ElementAt(0) == 1 || x.Reference.ListOfString.AsQueryable().ElementAt(1) == "Bar") .OrderBy(e => e.Id); @@ -502,21 +475,16 @@ public virtual async Task Predicate_based_on_element_of_json_array_of_primitives } } - protected abstract Task SeedArrayOfPrimitives(MyContextArrayOfPrimitives ctx); + protected abstract Task SeedArrayOfPrimitives(DbContext ctx); - protected class MyContextArrayOfPrimitives(DbContextOptions options) : DbContext(options) + protected virtual void BuildModelArrayOfPrimitives(ModelBuilder modelBuilder) { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne( - x => x.Reference, b => b.ToJson()); + modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); + modelBuilder.Entity().OwnsOne( + x => x.Reference, b => b.ToJson("Reference", JsonColumnType)); - modelBuilder.Entity().OwnsMany( - x => x.Collection, b => b.ToJson()); - } + modelBuilder.Entity().OwnsMany( + x => x.Collection, b => b.ToJson("Collection", JsonColumnType)); } public class MyEntityArrayOfPrimitives @@ -540,12 +508,11 @@ public class MyJsonEntityArrayOfPrimitives [MemberData(nameof(IsAsyncData))] public virtual async Task Junk_in_json_basic_tracking(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedJunkInJson); + var contextFactory = await InitializeAsync(BuildModelJunkInJson, seed: SeedJunkInJson); using (var context = contextFactory.CreateContext()) { - var query = context.Entities; + var query = context.Set(); var result = async ? await query.ToListAsync() @@ -565,12 +532,11 @@ public virtual async Task Junk_in_json_basic_tracking(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Junk_in_json_basic_no_tracking(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedJunkInJson); + var contextFactory = await InitializeAsync(BuildModelJunkInJson, seed: SeedJunkInJson); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.AsNoTracking(); + var query = context.Set().AsNoTracking(); var result = async ? await query.ToListAsync() @@ -586,45 +552,47 @@ public virtual async Task Junk_in_json_basic_no_tracking(bool async) } } - protected abstract Task SeedJunkInJson(MyContextJunkInJson ctx); - - protected class MyContextJunkInJson(DbContextOptions options) : DbContext(options) - { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne( - x => x.Reference, b => - { - b.ToJson(); - b.OwnsOne(x => x.NestedReference); - b.OwnsMany(x => x.NestedCollection); - }); - modelBuilder.Entity().OwnsOne( - x => x.ReferenceWithCtor, b => - { - b.ToJson(); - b.OwnsOne(x => x.NestedReference); - b.OwnsMany(x => x.NestedCollection); - }); - modelBuilder.Entity().OwnsMany( - x => x.Collection, b => - { - b.ToJson(); - b.OwnsOne(x => x.NestedReference); - b.OwnsMany(x => x.NestedCollection); - }); - modelBuilder.Entity().OwnsMany( - x => x.CollectionWithCtor, b => - { - b.ToJson(); - b.OwnsOne(x => x.NestedReference); - b.OwnsMany(x => x.NestedCollection); - }); - } - } + protected abstract Task SeedJunkInJson(DbContext ctx); + + protected virtual void BuildModelJunkInJson(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.ToTable("Entities"); + b.Property(x => x.Id).ValueGeneratedNever(); + + b.OwnsOne( + x => x.Reference, b => + { + b.ToJson("Reference", JsonColumnType); + b.OwnsOne(x => x.NestedReference); + b.OwnsMany(x => x.NestedCollection); + }); + + b.OwnsOne( + x => x.ReferenceWithCtor, b => + { + b.ToJson("ReferenceWithCtor", JsonColumnType); + b.OwnsOne(x => x.NestedReference); + b.OwnsMany(x => x.NestedCollection); + }); + + b.OwnsMany( + x => x.Collection, b => + { + b.ToJson("Collection", JsonColumnType); + b.OwnsOne(x => x.NestedReference); + b.OwnsMany(x => x.NestedCollection); + }); + + b.OwnsMany( + x => x.CollectionWithCtor, b => + { + b.ToJson("CollectionWithCtor", JsonColumnType); + b.OwnsOne(x => x.NestedReference); + b.OwnsMany(x => x.NestedCollection); + }); + }); public class MyEntityJunkInJson { @@ -671,12 +639,11 @@ public class MyJsonEntityJunkInJsonWithCtorNested(DateTime doB) [MemberData(nameof(IsAsyncData))] public virtual async Task Tricky_buffering_basic(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedTrickyBuffering); + var contextFactory = await InitializeAsync(BuildModelTrickyBuffering, seed: SeedTrickyBuffering); using (var context = contextFactory.CreateContext()) { - var query = context.Entities; + var query = context.Set(); var result = async ? await query.ToListAsync() @@ -690,24 +657,22 @@ public virtual async Task Tricky_buffering_basic(bool async) } } - protected abstract Task SeedTrickyBuffering(MyContextTrickyBuffering ctx); - - protected class MyContextTrickyBuffering(DbContextOptions options) : DbContext(options) - { - public DbSet Entities { get; set; } + protected abstract Task SeedTrickyBuffering(DbContext ctx); - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne( - x => x.Reference, b => - { - b.ToJson(); - b.OwnsOne(x => x.NestedReference); - b.OwnsMany(x => x.NestedCollection); - }); - } - } + protected virtual void BuildModelTrickyBuffering(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.ToTable("Entities"); + b.Property(x => x.Id).ValueGeneratedNever(); + b.OwnsOne( + x => x.Reference, b => + { + b.ToJson("Reference", JsonColumnType); + b.OwnsOne(x => x.NestedReference); + b.OwnsMany(x => x.NestedCollection); + }); + }); public class MyEntityTrickyBuffering { @@ -736,12 +701,11 @@ public class MyJsonEntityTrickyBufferingNested [MemberData(nameof(IsAsyncData))] public virtual async Task Shadow_properties_basic_tracking(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedShadowProperties); + var contextFactory = await InitializeAsync(BuildModelShadowProperties, seed: SeedShadowProperties); using (var context = contextFactory.CreateContext()) { - var query = context.Entities; + var query = context.Set(); var result = async ? await query.ToListAsync() @@ -775,12 +739,11 @@ public virtual async Task Shadow_properties_basic_tracking(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Shadow_properties_basic_no_tracking(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedShadowProperties); + var contextFactory = await InitializeAsync(BuildModelShadowProperties, seed: SeedShadowProperties); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.AsNoTracking(); + var query = context.Set().AsNoTracking(); var result = async ? await query.ToListAsync() @@ -798,12 +761,11 @@ public virtual async Task Shadow_properties_basic_no_tracking(bool async) [MemberData(nameof(IsAsyncData))] public virtual async Task Project_shadow_properties_from_json_entity(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedShadowProperties); + var contextFactory = await InitializeAsync(BuildModelShadowProperties, seed: SeedShadowProperties); using (var context = contextFactory.CreateContext()) { - var query = context.Entities.Select( + var query = context.Set().Select( x => new { ShadowString = EF.Property(x.Reference, "ShadowString"), @@ -820,40 +782,44 @@ public virtual async Task Project_shadow_properties_from_json_entity(bool async) } } - protected abstract Task SeedShadowProperties(MyContextShadowProperties ctx); + protected abstract Task SeedShadowProperties(DbContext ctx); - protected class MyContextShadowProperties(DbContextOptions options) : DbContext(options) + protected virtual void BuildModelShadowProperties(ModelBuilder modelBuilder) { - public DbSet Entities { get; set; } + modelBuilder.Entity( + b => + { + b.ToTable("Entities"); + b.Property(x => x.Id).ValueGeneratedNever(); - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne( - x => x.Reference, b => - { - b.ToJson(); - b.Property("ShadowString"); - }); - modelBuilder.Entity().OwnsOne( - x => x.ReferenceWithCtor, b => - { - b.ToJson(); - b.Property("Shadow_Int").HasJsonPropertyName("ShadowInt"); - }); - modelBuilder.Entity().OwnsMany( - x => x.Collection, b => - { - b.ToJson(); - b.Property("ShadowDouble"); - }); - modelBuilder.Entity().OwnsMany( - x => x.CollectionWithCtor, b => - { - b.ToJson(); - b.Property("ShadowNullableByte"); - }); - } + b.OwnsOne( + x => x.Reference, b => + { + b.ToJson("Reference", JsonColumnType); + b.Property("ShadowString"); + }); + + b.OwnsOne( + x => x.ReferenceWithCtor, b => + { + b.ToJson("ReferenceWithCtor", JsonColumnType); + b.Property("Shadow_Int").HasJsonPropertyName("ShadowInt"); + }); + + b.OwnsMany( + x => x.Collection, b => + { + b.ToJson("Collection", JsonColumnType); + b.Property("ShadowDouble"); + }); + + b.OwnsMany( + x => x.CollectionWithCtor, b => + { + b.ToJson("CollectionWithCtor", JsonColumnType); + b.Property("ShadowNullableByte"); + }); + }); } public class MyEntityShadowProperties @@ -885,14 +851,15 @@ public class MyJsonEntityShadowPropertiesWithCtor(string name) [MemberData(nameof(IsAsyncData))] public virtual async Task Project_proxies_entity_with_json(bool async) { - var contextFactory = await InitializeAsync( + var contextFactory = await InitializeAsync( + onModelCreating: BuildModelLazyLoadingProxies, seed: SeedLazyLoadingProxies, onConfiguring: OnConfiguringLazyLoadingProxies, addServices: AddServicesLazyLoadingProxies); using (var context = contextFactory.CreateContext()) { - var query = context.Entities; + var query = context.Set(); var result = async ? await query.ToListAsync() @@ -908,7 +875,7 @@ protected void OnConfiguringLazyLoadingProxies(DbContextOptionsBuilder optionsBu protected IServiceCollection AddServicesLazyLoadingProxies(IServiceCollection addServices) => addServices.AddEntityFrameworkProxies(); - private Task SeedLazyLoadingProxies(MyContextLazyLoadingProxies ctx) + private Task SeedLazyLoadingProxies(DbContext ctx) { var r1 = new MyJsonEntityLazyLoadingProxiesWithCtor("r1", 1); var c11 = new MyJsonEntityLazyLoadingProxies { Name = "c11", Number = 11 }; @@ -940,20 +907,15 @@ private Task SeedLazyLoadingProxies(MyContextLazyLoadingProxies ctx) Collection = [c21, c22] }; - ctx.Entities.AddRange(e1, e2); + ctx.Set().AddRange(e1, e2); return ctx.SaveChangesAsync(); } - protected class MyContextLazyLoadingProxies(DbContextOptions options) : DbContext(options) + protected virtual void BuildModelLazyLoadingProxies(ModelBuilder modelBuilder) { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne(x => x.Reference, b => b.ToJson()); - modelBuilder.Entity().OwnsMany(x => x.Collection, b => b.ToJson()); - } + modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); + modelBuilder.Entity().OwnsOne(x => x.Reference, b => b.ToJson("Reference", JsonColumnType)); + modelBuilder.Entity().OwnsMany(x => x.Collection, b => b.ToJson("Collection", JsonColumnType)); } public class MyEntityLazyLoadingProxies @@ -985,12 +947,11 @@ public class MyJsonEntityLazyLoadingProxies [MemberData(nameof(IsAsyncData))] public virtual async Task Not_ICollection_basic_projection(bool async) { - var contextFactory = await InitializeAsync( - seed: SeedNotICollection); + var contextFactory = await InitializeAsync(BuildModelNotICollection, seed: SeedNotICollection); using (var context = contextFactory.CreateContext()) { - var query = context.Entities; + var query = context.Set(); var result = async ? await query.ToListAsync() @@ -1000,7 +961,7 @@ public virtual async Task Not_ICollection_basic_projection(bool async) } } - protected abstract Task SeedNotICollection(MyContextNotICollection ctx); + protected abstract Task SeedNotICollection(DbContext ctx); public class MyEntityNotICollection { @@ -1023,24 +984,25 @@ public class MyJsonNestedEntityNotICollection public int Bar { get; set; } } - public class MyContextNotICollection(DbContextOptions options) : DbContext(options) - { - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne( - cr => cr.Json, nb => - { - nb.ToJson(); - nb.OwnsMany(x => x.Collection); - }); - } - } + protected virtual void BuildModelNotICollection(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.ToTable("Entities"); + b.Property(x => x.Id).ValueGeneratedNever(); + b.OwnsOne( + cr => cr.Json, nb => + { + nb.ToJson("Json", JsonColumnType); + nb.OwnsMany(x => x.Collection); + }); + }); #endregion protected TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; + + protected virtual string JsonColumnType + => null; } diff --git a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs index 7004dac0a80..3c9e1d72cc7 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs @@ -21,12 +21,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().OwnsOne(x => x.OwnedReferenceRoot).ToJson(); modelBuilder.Entity().OwnsMany(x => x.OwnedCollectionRoot).ToJson(); - + modelBuilder.Entity().OwnsOne(x => x.OwnedReferenceRoot).ToJson("json_reference_custom_naming"); modelBuilder.Entity().OwnsMany(x => x.OwnedCollectionRoot).ToJson("json_collection_custom_naming"); - + modelBuilder.Entity().OwnsMany(x => x.OwnedCollection).ToJson(); - + modelBuilder.Entity( b => { diff --git a/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs index db55c4a6700..9044d53af71 100644 --- a/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs +++ b/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs @@ -651,7 +651,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con }); } - protected override string StoreName { get; } = "JsonQueryTest"; + protected override string StoreName + => "JsonQueryTest"; public override JsonQueryContext CreateContext() { diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs index 4d50437b494..ce165a2824d 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs @@ -1169,6 +1169,7 @@ public static IReadOnlyList CreateJsonEntitiesAllTypes() "S3" ], TestBooleanCollection = new[] { true, false }, + TestByteCollection = [], TestCharacterCollection = [ 'A', @@ -1263,6 +1264,7 @@ public static IReadOnlyList CreateJsonEntitiesAllTypes() "S3" ], TestBooleanCollection = new[] { true, false }, + TestByteCollection = [], TestCharacterCollection = [ 'A', diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerJsonTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerJsonTypeTest.cs new file mode 100644 index 00000000000..2cf801a0e46 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerJsonTypeTest.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable +using Microsoft.Data.SqlClient; + +namespace Microsoft.EntityFrameworkCore.Query; + +public class AdHocJsonQuerySqlServerJsonTypeTest : AdHocJsonQuerySqlServerTestBase +{ + public override async Task Contains_on_nested_collection_with_init_only_navigation(bool async) + // TODO:SQLJSON (See JsonTypeToFunction.cs) + => Assert.Equal( + "OpenJson support not yet supported for JSON native data type.", + (await Assert.ThrowsAsync( + () => base.Contains_on_nested_collection_with_init_only_navigation(async))).Message); + + protected override string StoreName + => "AdHocJsonQueryJsonTypeTest"; + + protected override string JsonColumnType + => "json"; +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTest.cs index 3f42c52b152..02bdd29574b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTest.cs @@ -1,384 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.Data.SqlClient; -using Microsoft.EntityFrameworkCore.Diagnostics.Internal; -using Microsoft.EntityFrameworkCore.SqlServer.Diagnostics.Internal; - namespace Microsoft.EntityFrameworkCore.Query; #nullable disable -public class AdHocJsonQuerySqlServerTest : AdHocJsonQueryTestBase +public class AdHocJsonQuerySqlServerTest : AdHocJsonQuerySqlServerTestBase { - protected override ITestStoreFactory TestStoreFactory - => SqlServerTestStoreFactory.Instance; - - protected override async Task Seed29219(MyContext29219 ctx) - { - var entity1 = new MyEntity29219 - { - Id = 1, - Reference = new MyJsonEntity29219 { NonNullableScalar = 10, NullableScalar = 11 }, - Collection = - [ - new() { NonNullableScalar = 100, NullableScalar = 101 }, - new() { NonNullableScalar = 200, NullableScalar = 201 }, - new() { NonNullableScalar = 300, NullableScalar = null } - ] - }; - - var entity2 = new MyEntity29219 - { - Id = 2, - Reference = new MyJsonEntity29219 { NonNullableScalar = 20, NullableScalar = null }, - Collection = [new() { NonNullableScalar = 1001, NullableScalar = null }] - }; - - ctx.Entities.AddRange(entity1, entity2); - await ctx.SaveChangesAsync(); - - await ctx.Database.ExecuteSqlAsync( - $$""" -INSERT INTO [Entities] ([Id], [Reference], [Collection]) -VALUES(3, N'{ "NonNullableScalar" : 30 }', N'[{ "NonNullableScalar" : 10001 }]') -"""); - } - - protected override async Task Seed30028(MyContext30028 ctx) - { - // complete - await ctx.Database.ExecuteSqlAsync( - $$$$""" -INSERT INTO [Entities] ([Id], [Json]) -VALUES( -1, -N'{"RootName":"e1","Collection":[{"BranchName":"e1 c1","Nested":{"LeafName":"e1 c1 l"}},{"BranchName":"e1 c2","Nested":{"LeafName":"e1 c2 l"}}],"OptionalReference":{"BranchName":"e1 or","Nested":{"LeafName":"e1 or l"}},"RequiredReference":{"BranchName":"e1 rr","Nested":{"LeafName":"e1 rr l"}}}') -"""); - - // missing collection - await ctx.Database.ExecuteSqlAsync( - $$$$""" -INSERT INTO [Entities] ([Id], [Json]) -VALUES( -2, -N'{"RootName":"e2","OptionalReference":{"BranchName":"e2 or","Nested":{"LeafName":"e2 or l"}},"RequiredReference":{"BranchName":"e2 rr","Nested":{"LeafName":"e2 rr l"}}}') -"""); - - // missing optional reference - await ctx.Database.ExecuteSqlAsync( - $$$$""" -INSERT INTO [Entities] ([Id], [Json]) -VALUES( -3, -N'{"RootName":"e3","Collection":[{"BranchName":"e3 c1","Nested":{"LeafName":"e3 c1 l"}},{"BranchName":"e3 c2","Nested":{"LeafName":"e3 c2 l"}}],"RequiredReference":{"BranchName":"e3 rr","Nested":{"LeafName":"e3 rr l"}}}') -"""); - - // missing required reference - await ctx.Database.ExecuteSqlAsync( - $$$$""" -INSERT INTO [Entities] ([Id], [Json]) -VALUES( -4, -N'{"RootName":"e4","Collection":[{"BranchName":"e4 c1","Nested":{"LeafName":"e4 c1 l"}},{"BranchName":"e4 c2","Nested":{"LeafName":"e4 c2 l"}}],"OptionalReference":{"BranchName":"e4 or","Nested":{"LeafName":"e4 or l"}}}') -"""); - } - - protected override Task Seed33046(Context33046 ctx) - => ctx.Database.ExecuteSqlAsync( - $$""" -INSERT INTO [Reviews] ([Rounds], [Id]) -VALUES(N'[{"RoundNumber":11,"SubRounds":[{"SubRoundNumber":111},{"SubRoundNumber":112}]}]', 1) -"""); - - protected override Task SeedArrayOfPrimitives(MyContextArrayOfPrimitives ctx) - { - var entity1 = new MyEntityArrayOfPrimitives - { - Id = 1, - Reference = new MyJsonEntityArrayOfPrimitives - { - IntArray = [1, 2, 3], - ListOfString = - [ - "Foo", - "Bar", - "Baz" - ] - }, - Collection = - [ - new() { IntArray = [111, 112, 113], ListOfString = ["Foo11", "Bar11"] }, - new() { IntArray = [211, 212, 213], ListOfString = ["Foo12", "Bar12"] } - ] - }; - - var entity2 = new MyEntityArrayOfPrimitives - { - Id = 2, - Reference = new MyJsonEntityArrayOfPrimitives - { - IntArray = [10, 20, 30], - ListOfString = - [ - "A", - "B", - "C" - ] - }, - Collection = - [ - new() { IntArray = [110, 120, 130], ListOfString = ["A1", "Z1"] }, - new() { IntArray = [210, 220, 230], ListOfString = ["A2", "Z2"] } - ] - }; - - ctx.Entities.AddRange(entity1, entity2); - return ctx.SaveChangesAsync(); - } - - protected override Task SeedJunkInJson(MyContextJunkInJson ctx) - => ctx.Database.ExecuteSqlAsync( - $$$$""" -INSERT INTO [Entities] ([Collection], [CollectionWithCtor], [Reference], [ReferenceWithCtor], [Id]) -VALUES( -N'[{"JunkReference":{"Something":"SomeValue" },"Name":"c11","JunkProperty1":50,"Number":11.5,"JunkCollection1":[],"JunkCollection2":[{"Foo":"junk value"}],"NestedCollection":[{"DoB":"2002-04-01T00:00:00","DummyProp":"Dummy value"},{"DoB":"2002-04-02T00:00:00","DummyReference":{"Foo":5}}],"NestedReference":{"DoB":"2002-03-01T00:00:00"}},{"Name":"c12","Number":12.5,"NestedCollection":[{"DoB":"2002-06-01T00:00:00"},{"DoB":"2002-06-02T00:00:00"}],"NestedDummy":59,"NestedReference":{"DoB":"2002-05-01T00:00:00"}}]', -N'[{"MyBool":true,"Name":"c11 ctor","JunkReference":{"Something":"SomeValue","JunkCollection":[{"Foo":"junk value"}]},"NestedCollection":[{"DoB":"2002-08-01T00:00:00"},{"DoB":"2002-08-02T00:00:00"}],"NestedReference":{"DoB":"2002-07-01T00:00:00"}},{"MyBool":false,"Name":"c12 ctor","NestedCollection":[{"DoB":"2002-10-01T00:00:00"},{"DoB":"2002-10-02T00:00:00"}],"JunkCollection":[{"Foo":"junk value"}],"NestedReference":{"DoB":"2002-09-01T00:00:00"}}]', -N'{"Name":"r1","JunkCollection":[{"Foo":"junk value"}],"JunkReference":{"Something":"SomeValue" },"Number":1.5,"NestedCollection":[{"DoB":"2000-02-01T00:00:00","JunkReference":{"Something":"SomeValue"}},{"DoB":"2000-02-02T00:00:00"}],"NestedReference":{"DoB":"2000-01-01T00:00:00"}}', -N'{"MyBool":true,"JunkCollection":[{"Foo":"junk value"}],"Name":"r1 ctor","JunkReference":{"Something":"SomeValue" },"NestedCollection":[{"DoB":"2001-02-01T00:00:00"},{"DoB":"2001-02-02T00:00:00"}],"NestedReference":{"JunkCollection":[{"Foo":"junk value"}],"DoB":"2001-01-01T00:00:00"}}', -1) -"""); - - protected override Task SeedTrickyBuffering(MyContextTrickyBuffering ctx) - => ctx.Database.ExecuteSqlAsync( - $$$""" -INSERT INTO [Entities] ([Reference], [Id]) -VALUES( -N'{"Name": "r1", "Number": 7, "JunkReference":{"Something": "SomeValue" }, "JunkCollection": [{"Foo": "junk value"}], "NestedReference": {"DoB": "2000-01-01T00:00:00"}, "NestedCollection": [{"DoB": "2000-02-01T00:00:00", "JunkReference": {"Something": "SomeValue"}}, {"DoB": "2000-02-02T00:00:00"}]}',1) -"""); - - protected override Task SeedShadowProperties(MyContextShadowProperties ctx) - => ctx.Database.ExecuteSqlAsync( - $$""" -INSERT INTO [Entities] ([Collection], [CollectionWithCtor], [Reference], [ReferenceWithCtor], [Id], [Name]) -VALUES( -N'[{"Name":"e1_c1","ShadowDouble":5.5},{"ShadowDouble":20.5,"Name":"e1_c2"}]', -N'[{"Name":"e1_c1 ctor","ShadowNullableByte":6},{"ShadowNullableByte":null,"Name":"e1_c2 ctor"}]', -N'{"Name":"e1_r", "ShadowString":"Foo"}', -N'{"ShadowInt":143,"Name":"e1_r ctor"}', -1, -N'e1') -"""); - - protected override async Task SeedNotICollection(MyContextNotICollection ctx) - { - await ctx.Database.ExecuteSqlAsync( - $$""" -INSERT INTO [Entities] ([Json], [Id]) -VALUES( -N'{"Collection":[{"Bar":11,"Foo":"c11"},{"Bar":12,"Foo":"c12"},{"Bar":13,"Foo":"c13"}]}', -1) -"""); - - await ctx.Database.ExecuteSqlAsync( - $$$""" -INSERT INTO [Entities] ([Json], [Id]) -VALUES( -N'{"Collection":[{"Bar":21,"Foo":"c21"},{"Bar":22,"Foo":"c22"}]}', -2) -"""); - } - - #region EnumLegacyValues - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task Read_enum_property_with_legacy_values(bool async) - { - var contextFactory = await InitializeAsync( - seed: SeedEnumLegacyValues); - - using (var context = contextFactory.CreateContext()) - { - var query = context.Entities.Select( - x => new - { - x.Reference.IntEnum, - x.Reference.ByteEnum, - x.Reference.LongEnum, - x.Reference.NullableEnum - }); - - var exception = async - ? await (Assert.ThrowsAsync(() => query.ToListAsync())) - : Assert.Throws(() => query.ToList()); - - // Conversion failed when converting the nvarchar value '...' to data type int - Assert.Equal(245, exception.Number); - } - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task Read_json_entity_with_enum_properties_with_legacy_values(bool async) - { - var contextFactory = await InitializeAsync( - seed: SeedEnumLegacyValues, - shouldLogCategory: c => c == DbLoggerCategory.Query.Name); - - using (var context = contextFactory.CreateContext()) - { - var query = context.Entities.Select(x => x.Reference).AsNoTracking(); - - var result = async - ? await query.ToListAsync() - : query.ToList(); - - Assert.Equal(1, result.Count); - Assert.Equal(ByteEnumLegacyValues.Redmond, result[0].ByteEnum); - Assert.Equal(IntEnumLegacyValues.Foo, result[0].IntEnum); - Assert.Equal(LongEnumLegacyValues.Three, result[0].LongEnum); - Assert.Equal(ULongEnumLegacyValues.Three, result[0].ULongEnum); - Assert.Equal(IntEnumLegacyValues.Bar, result[0].NullableEnum); - } - - var testLogger = new TestLogger(); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ByteEnumLegacyValues)))); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(IntEnumLegacyValues)))); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(LongEnumLegacyValues)))); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ULongEnumLegacyValues)))); - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual async Task Read_json_entity_collection_with_enum_properties_with_legacy_values(bool async) - { - var contextFactory = await InitializeAsync( - seed: SeedEnumLegacyValues, - shouldLogCategory: c => c == DbLoggerCategory.Query.Name); - - using (var context = contextFactory.CreateContext()) - { - var query = context.Entities.Select(x => x.Collection).AsNoTracking(); - - var result = async - ? await query.ToListAsync() - : query.ToList(); - - Assert.Equal(1, result.Count); - Assert.Equal(2, result[0].Count); - Assert.Equal(ByteEnumLegacyValues.Bellevue, result[0][0].ByteEnum); - Assert.Equal(IntEnumLegacyValues.Foo, result[0][0].IntEnum); - Assert.Equal(LongEnumLegacyValues.One, result[0][0].LongEnum); - Assert.Equal(ULongEnumLegacyValues.One, result[0][0].ULongEnum); - Assert.Equal(IntEnumLegacyValues.Bar, result[0][0].NullableEnum); - Assert.Equal(ByteEnumLegacyValues.Seattle, result[0][1].ByteEnum); - Assert.Equal(IntEnumLegacyValues.Baz, result[0][1].IntEnum); - Assert.Equal(LongEnumLegacyValues.Two, result[0][1].LongEnum); - Assert.Equal(ULongEnumLegacyValues.Two, result[0][1].ULongEnum); - Assert.Null(result[0][1].NullableEnum); - } - - var testLogger = new TestLogger(); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ByteEnumLegacyValues)))); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(IntEnumLegacyValues)))); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(LongEnumLegacyValues)))); - Assert.Single( - ListLoggerFactory.Log.Where( - l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ULongEnumLegacyValues)))); - } - - private Task SeedEnumLegacyValues(MyContextEnumLegacyValues ctx) - => ctx.Database.ExecuteSqlAsync( - $$""" -INSERT INTO [Entities] ([Collection], [Reference], [Id], [Name]) -VALUES( -N'[{"ByteEnum":"Bellevue","IntEnum":"Foo","LongEnum":"One","ULongEnum":"One","Name":"e1_c1","NullableEnum":"Bar"},{"ByteEnum":"Seattle","IntEnum":"Baz","LongEnum":"Two","ULongEnum":"Two","Name":"e1_c2","NullableEnum":null}]', -N'{"ByteEnum":"Redmond","IntEnum":"Foo","LongEnum":"Three","ULongEnum":"Three","Name":"e1_r","NullableEnum":"Bar"}', -1, -N'e1') -"""); - - private class MyContextEnumLegacyValues(DbContextOptions options) : DbContext((new DbContextOptionsBuilder(options)).ConfigureWarnings(b => b.Log(CoreEventId.StringEnumValueInJson)).Options) - { - - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public DbSet Entities { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().OwnsOne(x => x.Reference, b => b.ToJson()); - modelBuilder.Entity().OwnsMany(x => x.Collection, b => b.ToJson()); - } - } - - private class MyEntityEnumLegacyValues - { - public int Id { get; set; } - public string Name { get; set; } - - public MyJsonEntityEnumLegacyValues Reference { get; set; } - public List Collection { get; set; } - } - - private class MyJsonEntityEnumLegacyValues - { - public string Name { get; set; } - - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public IntEnumLegacyValues IntEnum { get; set; } - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public ByteEnumLegacyValues ByteEnum { get; set; } - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public LongEnumLegacyValues LongEnum { get; set; } - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public ULongEnumLegacyValues ULongEnum { get; set; } - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public IntEnumLegacyValues? NullableEnum { get; set; } - } - - private enum IntEnumLegacyValues - { - Foo = int.MinValue, - Bar, - Baz = int.MaxValue, - } - - private enum ByteEnumLegacyValues : byte - { - Seattle, - Redmond, - Bellevue = 255, - } - - private enum LongEnumLegacyValues : long - { - One = long.MinValue, - Two = 1, - Three = long.MaxValue, - } - - private enum ULongEnumLegacyValues : ulong - { - One = ulong.MinValue, - Two = 1, - Three = ulong.MaxValue, - } - - #endregion } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTestBase.cs new file mode 100644 index 00000000000..651cd8b8b08 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocJsonQuerySqlServerTestBase.cs @@ -0,0 +1,385 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore.Diagnostics.Internal; +using Microsoft.EntityFrameworkCore.SqlServer.Diagnostics.Internal; + +namespace Microsoft.EntityFrameworkCore.Query; + +public abstract class AdHocJsonQuerySqlServerTestBase : AdHocJsonQueryTestBase +{ + protected override ITestStoreFactory TestStoreFactory + => SqlServerTestStoreFactory.Instance; + + protected override async Task Seed29219(DbContext ctx) + { + var entity1 = new MyEntity29219 + { + Id = 1, + Reference = new MyJsonEntity29219 { NonNullableScalar = 10, NullableScalar = 11 }, + Collection = + [ + new() { NonNullableScalar = 100, NullableScalar = 101 }, + new() { NonNullableScalar = 200, NullableScalar = 201 }, + new() { NonNullableScalar = 300, NullableScalar = null } + ] + }; + + var entity2 = new MyEntity29219 + { + Id = 2, + Reference = new MyJsonEntity29219 { NonNullableScalar = 20, NullableScalar = null }, + Collection = [new() { NonNullableScalar = 1001, NullableScalar = null }] + }; + + ctx.AddRange(entity1, entity2); + await ctx.SaveChangesAsync(); + + await ctx.Database.ExecuteSqlAsync( + $$""" +INSERT INTO [Entities] ([Id], [Reference], [Collection]) +VALUES(3, N'{ "NonNullableScalar" : 30 }', N'[{ "NonNullableScalar" : 10001 }]') +"""); + } + + protected override async Task Seed30028(DbContext ctx) + { + // complete + await ctx.Database.ExecuteSqlAsync( + $$$$""" +INSERT INTO [Entities] ([Id], [Json]) +VALUES( +1, +N'{"RootName":"e1","Collection":[{"BranchName":"e1 c1","Nested":{"LeafName":"e1 c1 l"}},{"BranchName":"e1 c2","Nested":{"LeafName":"e1 c2 l"}}],"OptionalReference":{"BranchName":"e1 or","Nested":{"LeafName":"e1 or l"}},"RequiredReference":{"BranchName":"e1 rr","Nested":{"LeafName":"e1 rr l"}}}') +"""); + + // missing collection + await ctx.Database.ExecuteSqlAsync( + $$$$""" +INSERT INTO [Entities] ([Id], [Json]) +VALUES( +2, +N'{"RootName":"e2","OptionalReference":{"BranchName":"e2 or","Nested":{"LeafName":"e2 or l"}},"RequiredReference":{"BranchName":"e2 rr","Nested":{"LeafName":"e2 rr l"}}}') +"""); + + // missing optional reference + await ctx.Database.ExecuteSqlAsync( + $$$$""" +INSERT INTO [Entities] ([Id], [Json]) +VALUES( +3, +N'{"RootName":"e3","Collection":[{"BranchName":"e3 c1","Nested":{"LeafName":"e3 c1 l"}},{"BranchName":"e3 c2","Nested":{"LeafName":"e3 c2 l"}}],"RequiredReference":{"BranchName":"e3 rr","Nested":{"LeafName":"e3 rr l"}}}') +"""); + + // missing required reference + await ctx.Database.ExecuteSqlAsync( + $$$$""" +INSERT INTO [Entities] ([Id], [Json]) +VALUES( +4, +N'{"RootName":"e4","Collection":[{"BranchName":"e4 c1","Nested":{"LeafName":"e4 c1 l"}},{"BranchName":"e4 c2","Nested":{"LeafName":"e4 c2 l"}}],"OptionalReference":{"BranchName":"e4 or","Nested":{"LeafName":"e4 or l"}}}') +"""); + } + + protected override Task Seed33046(DbContext ctx) + => ctx.Database.ExecuteSqlAsync( + $$""" +INSERT INTO [Reviews] ([Rounds], [Id]) +VALUES(N'[{"RoundNumber":11,"SubRounds":[{"SubRoundNumber":111},{"SubRoundNumber":112}]}]', 1) +"""); + + protected override Task SeedArrayOfPrimitives(DbContext ctx) + { + var entity1 = new MyEntityArrayOfPrimitives + { + Id = 1, + Reference = new MyJsonEntityArrayOfPrimitives + { + IntArray = [1, 2, 3], + ListOfString = + [ + "Foo", + "Bar", + "Baz" + ] + }, + Collection = + [ + new() { IntArray = [111, 112, 113], ListOfString = ["Foo11", "Bar11"] }, + new() { IntArray = [211, 212, 213], ListOfString = ["Foo12", "Bar12"] } + ] + }; + + var entity2 = new MyEntityArrayOfPrimitives + { + Id = 2, + Reference = new MyJsonEntityArrayOfPrimitives + { + IntArray = [10, 20, 30], + ListOfString = + [ + "A", + "B", + "C" + ] + }, + Collection = + [ + new() { IntArray = [110, 120, 130], ListOfString = ["A1", "Z1"] }, + new() { IntArray = [210, 220, 230], ListOfString = ["A2", "Z2"] } + ] + }; + + ctx.AddRange(entity1, entity2); + return ctx.SaveChangesAsync(); + } + + protected override Task SeedJunkInJson(DbContext ctx) + => ctx.Database.ExecuteSqlAsync( + $$$$""" +INSERT INTO [Entities] ([Collection], [CollectionWithCtor], [Reference], [ReferenceWithCtor], [Id]) +VALUES( +N'[{"JunkReference":{"Something":"SomeValue" },"Name":"c11","JunkProperty1":50,"Number":11.5,"JunkCollection1":[],"JunkCollection2":[{"Foo":"junk value"}],"NestedCollection":[{"DoB":"2002-04-01T00:00:00","DummyProp":"Dummy value"},{"DoB":"2002-04-02T00:00:00","DummyReference":{"Foo":5}}],"NestedReference":{"DoB":"2002-03-01T00:00:00"}},{"Name":"c12","Number":12.5,"NestedCollection":[{"DoB":"2002-06-01T00:00:00"},{"DoB":"2002-06-02T00:00:00"}],"NestedDummy":59,"NestedReference":{"DoB":"2002-05-01T00:00:00"}}]', +N'[{"MyBool":true,"Name":"c11 ctor","JunkReference":{"Something":"SomeValue","JunkCollection":[{"Foo":"junk value"}]},"NestedCollection":[{"DoB":"2002-08-01T00:00:00"},{"DoB":"2002-08-02T00:00:00"}],"NestedReference":{"DoB":"2002-07-01T00:00:00"}},{"MyBool":false,"Name":"c12 ctor","NestedCollection":[{"DoB":"2002-10-01T00:00:00"},{"DoB":"2002-10-02T00:00:00"}],"JunkCollection":[{"Foo":"junk value"}],"NestedReference":{"DoB":"2002-09-01T00:00:00"}}]', +N'{"Name":"r1","JunkCollection":[{"Foo":"junk value"}],"JunkReference":{"Something":"SomeValue" },"Number":1.5,"NestedCollection":[{"DoB":"2000-02-01T00:00:00","JunkReference":{"Something":"SomeValue"}},{"DoB":"2000-02-02T00:00:00"}],"NestedReference":{"DoB":"2000-01-01T00:00:00"}}', +N'{"MyBool":true,"JunkCollection":[{"Foo":"junk value"}],"Name":"r1 ctor","JunkReference":{"Something":"SomeValue" },"NestedCollection":[{"DoB":"2001-02-01T00:00:00"},{"DoB":"2001-02-02T00:00:00"}],"NestedReference":{"JunkCollection":[{"Foo":"junk value"}],"DoB":"2001-01-01T00:00:00"}}', +1) +"""); + + protected override Task SeedTrickyBuffering(DbContext ctx) + => ctx.Database.ExecuteSqlAsync( + $$$""" +INSERT INTO [Entities] ([Reference], [Id]) +VALUES( +N'{"Name": "r1", "Number": 7, "JunkReference":{"Something": "SomeValue" }, "JunkCollection": [{"Foo": "junk value"}], "NestedReference": {"DoB": "2000-01-01T00:00:00"}, "NestedCollection": [{"DoB": "2000-02-01T00:00:00", "JunkReference": {"Something": "SomeValue"}}, {"DoB": "2000-02-02T00:00:00"}]}',1) +"""); + + protected override Task SeedShadowProperties(DbContext ctx) + => ctx.Database.ExecuteSqlAsync( + $$""" +INSERT INTO [Entities] ([Collection], [CollectionWithCtor], [Reference], [ReferenceWithCtor], [Id], [Name]) +VALUES( +N'[{"Name":"e1_c1","ShadowDouble":5.5},{"ShadowDouble":20.5,"Name":"e1_c2"}]', +N'[{"Name":"e1_c1 ctor","ShadowNullableByte":6},{"ShadowNullableByte":null,"Name":"e1_c2 ctor"}]', +N'{"Name":"e1_r", "ShadowString":"Foo"}', +N'{"ShadowInt":143,"Name":"e1_r ctor"}', +1, +N'e1') +"""); + + protected override async Task SeedNotICollection(DbContext ctx) + { + await ctx.Database.ExecuteSqlAsync( + $$""" +INSERT INTO [Entities] ([Json], [Id]) +VALUES( +N'{"Collection":[{"Bar":11,"Foo":"c11"},{"Bar":12,"Foo":"c12"},{"Bar":13,"Foo":"c13"}]}', +1) +"""); + + await ctx.Database.ExecuteSqlAsync( + $$$""" +INSERT INTO [Entities] ([Json], [Id]) +VALUES( +N'{"Collection":[{"Bar":21,"Foo":"c21"},{"Bar":22,"Foo":"c22"}]}', +2) +"""); + } + + #region EnumLegacyValues + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Read_enum_property_with_legacy_values(bool async) + { + var contextFactory = await InitializeAsync( + onModelCreating: BuildModelEnumLegacyValues, + onConfiguring: b => b.ConfigureWarnings(b => b.Log(CoreEventId.StringEnumValueInJson)), + seed: SeedEnumLegacyValues); + + using (var context = contextFactory.CreateContext()) + { + var query = context.Set().Select( + x => new + { + x.Reference.IntEnum, + x.Reference.ByteEnum, + x.Reference.LongEnum, + x.Reference.NullableEnum + }); + + var exception = async + ? await (Assert.ThrowsAsync(() => query.ToListAsync())) + : Assert.Throws(() => query.ToList()); + + // Conversion failed when converting the nvarchar value '...' to data type int + Assert.Equal(245, exception.Number); + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Read_json_entity_with_enum_properties_with_legacy_values(bool async) + { + var contextFactory = await InitializeAsync( + onModelCreating: BuildModelEnumLegacyValues, + onConfiguring: b => b.ConfigureWarnings(b => b.Log(CoreEventId.StringEnumValueInJson)), + seed: SeedEnumLegacyValues, + shouldLogCategory: c => c == DbLoggerCategory.Query.Name); + + using (var context = contextFactory.CreateContext()) + { + var query = context.Set().Select(x => x.Reference).AsNoTracking(); + + var result = async + ? await query.ToListAsync() + : query.ToList(); + + Assert.Equal(1, result.Count); + Assert.Equal(ByteEnumLegacyValues.Redmond, result[0].ByteEnum); + Assert.Equal(IntEnumLegacyValues.Foo, result[0].IntEnum); + Assert.Equal(LongEnumLegacyValues.Three, result[0].LongEnum); + Assert.Equal(ULongEnumLegacyValues.Three, result[0].ULongEnum); + Assert.Equal(IntEnumLegacyValues.Bar, result[0].NullableEnum); + } + + var testLogger = new TestLogger(); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ByteEnumLegacyValues)))); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(IntEnumLegacyValues)))); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(LongEnumLegacyValues)))); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ULongEnumLegacyValues)))); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Read_json_entity_collection_with_enum_properties_with_legacy_values(bool async) + { + var contextFactory = await InitializeAsync( + onModelCreating: BuildModelEnumLegacyValues, + onConfiguring: b => b.ConfigureWarnings(b => b.Log(CoreEventId.StringEnumValueInJson)), + seed: SeedEnumLegacyValues, + shouldLogCategory: c => c == DbLoggerCategory.Query.Name); + + using (var context = contextFactory.CreateContext()) + { + var query = context.Set().Select(x => x.Collection).AsNoTracking(); + + var result = async + ? await query.ToListAsync() + : query.ToList(); + + Assert.Equal(1, result.Count); + Assert.Equal(2, result[0].Count); + Assert.Equal(ByteEnumLegacyValues.Bellevue, result[0][0].ByteEnum); + Assert.Equal(IntEnumLegacyValues.Foo, result[0][0].IntEnum); + Assert.Equal(LongEnumLegacyValues.One, result[0][0].LongEnum); + Assert.Equal(ULongEnumLegacyValues.One, result[0][0].ULongEnum); + Assert.Equal(IntEnumLegacyValues.Bar, result[0][0].NullableEnum); + Assert.Equal(ByteEnumLegacyValues.Seattle, result[0][1].ByteEnum); + Assert.Equal(IntEnumLegacyValues.Baz, result[0][1].IntEnum); + Assert.Equal(LongEnumLegacyValues.Two, result[0][1].LongEnum); + Assert.Equal(ULongEnumLegacyValues.Two, result[0][1].ULongEnum); + Assert.Null(result[0][1].NullableEnum); + } + + var testLogger = new TestLogger(); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ByteEnumLegacyValues)))); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(IntEnumLegacyValues)))); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(LongEnumLegacyValues)))); + Assert.Single( + ListLoggerFactory.Log.Where( + l => l.Message == CoreResources.LogStringEnumValueInJson(testLogger).GenerateMessage(nameof(ULongEnumLegacyValues)))); + } + + private Task SeedEnumLegacyValues(DbContext ctx) + => ctx.Database.ExecuteSqlAsync( + $$""" +INSERT INTO [Entities] ([Collection], [Reference], [Id], [Name]) +VALUES( +N'[{"ByteEnum":"Bellevue","IntEnum":"Foo","LongEnum":"One","ULongEnum":"One","Name":"e1_c1","NullableEnum":"Bar"},{"ByteEnum":"Seattle","IntEnum":"Baz","LongEnum":"Two","ULongEnum":"Two","Name":"e1_c2","NullableEnum":null}]', +N'{"ByteEnum":"Redmond","IntEnum":"Foo","LongEnum":"Three","ULongEnum":"Three","Name":"e1_r","NullableEnum":"Bar"}', +1, +N'e1') +"""); + + protected virtual void BuildModelEnumLegacyValues(ModelBuilder modelBuilder) + => modelBuilder.Entity( + b => + { + b.ToTable("Entities"); + b.Property(x => x.Id).ValueGeneratedNever(); + b.OwnsOne(x => x.Reference, b => b.ToJson("Reference", JsonColumnType)); + b.OwnsMany(x => x.Collection, b => b.ToJson("Collection", JsonColumnType)); + }); + + private class MyEntityEnumLegacyValues + { + public int Id { get; set; } + public string Name { get; set; } + + public MyJsonEntityEnumLegacyValues Reference { get; set; } + public List Collection { get; set; } + } + + private class MyJsonEntityEnumLegacyValues + { + public string Name { get; set; } + + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public IntEnumLegacyValues IntEnum { get; set; } + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public ByteEnumLegacyValues ByteEnum { get; set; } + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public LongEnumLegacyValues LongEnum { get; set; } + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public ULongEnumLegacyValues ULongEnum { get; set; } + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public IntEnumLegacyValues? NullableEnum { get; set; } + } + + private enum IntEnumLegacyValues + { + Foo = int.MinValue, + Bar, + Baz = int.MaxValue, + } + + private enum ByteEnumLegacyValues : byte + { + Seattle, + Redmond, + Bellevue = 255, + } + + private enum LongEnumLegacyValues : long + { + One = long.MinValue, + Two = 1, + Three = long.MaxValue, + } + + private enum ULongEnumLegacyValues : ulong + { + One = ulong.MinValue, + Two = 1, + Three = ulong.MaxValue, + } + + #endregion +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/JsonQueryJsonTypeSqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Query/JsonQueryJsonTypeSqlServerFixture.cs new file mode 100644 index 00000000000..4a8f92bbe3c --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/JsonQueryJsonTypeSqlServerFixture.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable +using Microsoft.EntityFrameworkCore.TestModels.JsonQuery; + +namespace Microsoft.EntityFrameworkCore.Query; + +public class JsonQueryJsonTypeSqlServerFixture : JsonQuerySqlServerFixture +{ + protected override string StoreName + => "JsonQueryJsonTypeTest"; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.OwnedReferenceRoot).ToJson("OwnedReferenceRoot", "json"); + b.OwnsMany(x => x.OwnedCollectionRoot).ToJson("OwnedCollectionRoot", "json"); + }); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.OwnedReferenceRoot).ToJson("json_reference_custom_naming", "json"); + b.OwnsMany(x => x.OwnedCollectionRoot).ToJson("json_collection_custom_naming", "json"); + }); + + modelBuilder.Entity().OwnsMany(x => x.OwnedCollection).ToJson("OwnedCollection", "json"); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.ReferenceOnBase).ToJson("ReferenceOnBase", "json"); + b.OwnsMany(x => x.CollectionOnBase).ToJson("CollectionOnBase", "json"); + }); + + modelBuilder.Entity( + b => + { + b.HasBaseType(); + b.OwnsOne(x => x.ReferenceOnDerived).ToJson("ReferenceOnDerived", "json"); + b.OwnsMany(x => x.CollectionOnDerived).ToJson("CollectionOnDerived", "json"); + }); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.Reference).ToJson("Reference", "json"); + b.OwnsMany(x => x.Collection).ToJson("Collection", "json"); + b.PrimitiveCollection(e => e.TestDefaultStringCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestMaxLengthStringCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestInt16Collection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestInt32Collection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestDecimalCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestDateTimeCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestDateTimeOffsetCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestTimeSpanCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestInt64Collection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestDoubleCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestSingleCollection).HasColumnType("json").IsRequired(); + b.PrimitiveCollection(e => e.TestBooleanCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestCharacterCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestByteCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestGuidCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestUnsignedInt16Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestUnsignedInt32Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestUnsignedInt64Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestSignedByteCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableInt32Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestEnumCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestEnumWithIntConverterCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableEnumCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableEnumWithIntConverterCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableEnumWithConverterThatHandlesNullsCollection).HasColumnType("json"); + }); + + modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson("Reference", "json"); + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/JsonQueryJsonTypeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/JsonQueryJsonTypeSqlServerTest.cs new file mode 100644 index 00000000000..b372f583b13 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/JsonQueryJsonTypeSqlServerTest.cs @@ -0,0 +1,3155 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore.TestModels.JsonQuery; + +namespace Microsoft.EntityFrameworkCore.Query; + +public class JsonQueryJsonTypeSqlServerTest : JsonQueryRelationalTestBase +{ + public JsonQueryJsonTypeSqlServerTest(JsonQueryJsonTypeSqlServerFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + public override async Task Basic_json_projection_owner_entity(bool async) + { + await base.Basic_json_projection_owner_entity(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_NoTracking(bool async) + { + await base.Basic_json_projection_owner_entity_NoTracking(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owner_entity_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_duplicated(bool async) + { + await base.Basic_json_projection_owner_entity_duplicated(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_duplicated_NoTracking(bool async) + { + await base.Basic_json_projection_owner_entity_duplicated_NoTracking(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Name], [j].[OwnedCollection], [j].[OwnedCollection] +FROM [JsonEntitiesSingleOwned] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_duplicated_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owner_entity_duplicated_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Name], [j].[OwnedCollection], [j].[OwnedCollection] +FROM [JsonEntitiesSingleOwned] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_twice(bool async) + { + await base.Basic_json_projection_owner_entity_twice(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_twice_NoTracking(bool async) + { + await base.Basic_json_projection_owner_entity_twice_NoTracking(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owner_entity_twice_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owner_entity_twice_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_reference_root(bool async) + { + await base.Basic_json_projection_owned_reference_root(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_reference_root_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owned_reference_root_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_reference_duplicated(bool async) + { + await base.Basic_json_projection_owned_reference_duplicated(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch') +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Basic_json_projection_owned_reference_duplicated_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owned_reference_duplicated_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch') +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Basic_json_projection_owned_reference_duplicated2(bool async) + { + await base.Basic_json_projection_owned_reference_duplicated2(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf') +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Basic_json_projection_owned_reference_duplicated2_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owned_reference_duplicated2_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf') +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Basic_json_projection_owned_collection_root(bool async) + { + await base.Basic_json_projection_owned_collection_root(async); + + AssertSql( + """ +SELECT [j].[OwnedCollectionRoot], [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_collection_root_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owned_collection_root_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[OwnedCollectionRoot], [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_reference_branch(bool async) + { + await base.Basic_json_projection_owned_reference_branch(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_reference_branch_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owned_reference_branch_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_collection_branch(bool async) + { + await base.Basic_json_projection_owned_collection_branch(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_collection_branch_NoTrackingWithIdentityResolution(bool async) + { + await base.Basic_json_projection_owned_collection_branch_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_reference_leaf(bool async) + { + await base.Basic_json_projection_owned_reference_leaf(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_owned_collection_leaf(bool async) + { + await base.Basic_json_projection_owned_collection_leaf(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Basic_json_projection_scalar(bool async) + { + await base.Basic_json_projection_scalar(async); + + AssertSql( + """ +SELECT JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_scalar_length(bool async) + { + await base.Json_scalar_length(async); + + AssertSql( + """ +SELECT [j].[Name] +FROM [JsonEntitiesBasic] AS [j] +WHERE CAST(LEN(JSON_VALUE([j].[OwnedReferenceRoot], '$.Name')) AS int) > 2 +"""); + } + + public override async Task Basic_json_projection_enum_inside_json_entity(bool async) + { + await base.Basic_json_projection_enum_inside_json_entity(async); + + AssertSql( + """ +SELECT [j].[Id], CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.Enum') AS int) AS [Enum] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_enum_with_custom_conversion(bool async) + { + await base.Json_projection_enum_with_custom_conversion(async); + + AssertSql( + """ +SELECT [j].[Id], CAST(JSON_VALUE([j].[json_reference_custom_naming], '$."1CustomEnum"') AS int) AS [Enum] +FROM [JsonEntitiesCustomNaming] AS [j] +"""); + } + + public override async Task Json_projection_with_deduplication(bool async) + { + await base.Json_projection_with_deduplication(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_with_deduplication_reverse_order(bool async) + { + await base.Json_projection_with_deduplication_reverse_order(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j].[Id], [j].[OwnedReferenceRoot], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_property_in_predicate(bool async) + { + await base.Json_property_in_predicate(async); + + AssertSql( + """ +SELECT [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +WHERE CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.Fraction') AS decimal(18,2)) < 20.5 +"""); + } + + public override async Task Json_subquery_property_pushdown_length(bool async) + { + await base.Json_subquery_property_pushdown_length(async); + + AssertSql( + """ +@__p_0='3' + +SELECT CAST(LEN([j1].[c]) AS int) +FROM ( + SELECT DISTINCT [j0].[c] + FROM ( + SELECT TOP(@__p_0) JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') AS [c] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [j0] +) AS [j1] +"""); + } + + public override async Task Json_subquery_reference_pushdown_reference(bool async) + { + // TODO:SQLJSON Json type is not comparable + Assert.Equal( + "The json data type cannot be selected as DISTINCT because it is not comparable.", + (await Assert.ThrowsAsync(() => base.Json_subquery_reference_pushdown_reference(async))).Message); + + AssertSql( + """ +@__p_0='10' + +SELECT JSON_QUERY([j1].[c], '$.OwnedReferenceBranch'), [j1].[Id] +FROM ( + SELECT DISTINCT [j0].[c] AS [c], [j0].[Id] + FROM ( + SELECT TOP(@__p_0) [j].[OwnedReferenceRoot] AS [c], [j].[Id] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [j0] +) AS [j1] +"""); + } + + public override async Task Json_subquery_reference_pushdown_reference_anonymous_projection(bool async) + { + await base.Json_subquery_reference_pushdown_reference_anonymous_projection(async); + + AssertSql( + """ +@__p_0='10' + +SELECT JSON_QUERY([t0].[c], '$.OwnedReferenceSharedBranch'), [t0].[Id], CAST(LEN([t0].[c0]) AS int) +FROM ( + SELECT DISTINCT JSON_QUERY([t].[c],'$') AS [c], [t].[Id], [t].[c0] + FROM ( + SELECT TOP(@__p_0) JSON_QUERY([j].[json_reference_shared], '$') AS [c], [j].[Id], CAST(JSON_VALUE([j].[json_reference_shared], '$.OwnedReferenceSharedBranch.OwnedReferenceSharedLeaf.SomethingSomething') AS nvarchar(max)) AS [c0] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [t] +) AS [t0] +"""); + } + + public override async Task Json_subquery_reference_pushdown_reference_pushdown_anonymous_projection(bool async) + { + await base.Json_subquery_reference_pushdown_reference_pushdown_anonymous_projection(async); + + AssertSql( + """ +@__p_0='10' + +SELECT JSON_QUERY([t2].[c],'$.OwnedReferenceSharedLeaf'), [t2].[Id], JSON_QUERY([t2].[c], '$.OwnedCollectionSharedLeaf'), [t2].[Length] +FROM ( + SELECT DISTINCT JSON_QUERY([t1].[c],'$') AS [c], [t1].[Id], [t1].[Length] + FROM ( + SELECT TOP(@__p_0) JSON_QUERY([t0].[c], '$.OwnedReferenceSharedBranch') AS [c], [t0].[Id], CAST(LEN([t0].[Scalar]) AS int) AS [Length] + FROM ( + SELECT DISTINCT JSON_QUERY([t].[c],'$') AS [c], [t].[Id], [t].[Scalar] + FROM ( + SELECT TOP(@__p_0) JSON_QUERY([j].[json_reference_shared], '$') AS [c], [j].[Id], CAST(JSON_VALUE([j].[json_reference_shared], '$.OwnedReferenceSharedBranch.OwnedReferenceSharedLeaf.SomethingSomething') AS nvarchar(max)) AS [Scalar] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [t] + ) AS [t0] + ORDER BY CAST(LEN([t0].[Scalar]) AS int) + ) AS [t1] +) AS [t2] +"""); + } + + public override async Task Json_subquery_reference_pushdown_reference_pushdown_reference(bool async) + { + // TODO:SQLJSON Json type is not comparable + Assert.StartsWith( + "The json data type cannot be selected as DISTINCT because it is not comparable.", + (await Assert.ThrowsAsync(() => base.Json_subquery_reference_pushdown_reference_pushdown_reference(async))).Message); + + AssertSql( + """ +@__p_0='10' + +SELECT JSON_QUERY([j3].[c], '$.OwnedReferenceLeaf'), [j3].[Id] +FROM ( + SELECT DISTINCT [j2].[c] AS [c], [j2].[Id] + FROM ( + SELECT TOP(@__p_0) JSON_QUERY([j1].[c], '$.OwnedReferenceBranch') AS [c], [j1].[Id] + FROM ( + SELECT DISTINCT [j0].[c] AS [c], [j0].[Id], [j0].[c] AS [c0] + FROM ( + SELECT TOP(@__p_0) [j].[OwnedReferenceRoot] AS [c], [j].[Id] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [j0] + ) AS [j1] + ORDER BY JSON_VALUE([j1].[c0], '$.Name') + ) AS [j2] +) AS [j3] +"""); + } + + public override async Task Json_subquery_reference_pushdown_reference_pushdown_collection(bool async) + { + // TODO:SQLJSON Json type is not comparable + Assert.StartsWith( + "The json data type cannot be selected as DISTINCT because it is not comparable.", + (await Assert.ThrowsAsync(() => base.Json_subquery_reference_pushdown_reference_pushdown_collection(async))).Message); + + AssertSql( + """ +@__p_0='10' + +SELECT JSON_QUERY([j3].[c], '$.OwnedCollectionLeaf'), [j3].[Id] +FROM ( + SELECT DISTINCT [j2].[c] AS [c], [j2].[Id] + FROM ( + SELECT TOP(@__p_0) JSON_QUERY([j1].[c], '$.OwnedReferenceBranch') AS [c], [j1].[Id] + FROM ( + SELECT DISTINCT [j0].[c] AS [c], [j0].[Id], [j0].[c] AS [c0] + FROM ( + SELECT TOP(@__p_0) [j].[OwnedReferenceRoot] AS [c], [j].[Id] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [j0] + ) AS [j1] + ORDER BY JSON_VALUE([j1].[c0], '$.Name') + ) AS [j2] +) AS [j3] +"""); + } + + public override async Task Json_subquery_reference_pushdown_property(bool async) + { + // TODO:SQLJSON Json type is not comparable + Assert.Equal( + "The json data type cannot be selected as DISTINCT because it is not comparable.", + (await Assert.ThrowsAsync(() => base.Json_subquery_reference_pushdown_property(async))).Message); + + AssertSql( + """ +@__p_0='10' + +SELECT JSON_VALUE([j1].[c], '$.SomethingSomething') +FROM ( + SELECT DISTINCT [j0].[c] AS [c], [j0].[Id] + FROM ( + SELECT TOP(@__p_0) JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf') AS [c], [j].[Id] + FROM [JsonEntitiesBasic] AS [j] + ORDER BY [j].[Id] + ) AS [j0] +) AS [j1] +"""); + } + + public override async Task Custom_naming_projection_owner_entity(bool async) + { + await base.Custom_naming_projection_owner_entity(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Title], [j].[json_collection_custom_naming], [j].[json_reference_custom_naming] +FROM [JsonEntitiesCustomNaming] AS [j] +"""); + } + + public override async Task Custom_naming_projection_owned_reference(bool async) + { + await base.Custom_naming_projection_owned_reference(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[json_reference_custom_naming], '$."Custom#OwnedReferenceBranch\u0060-=[]\\;\u0027,./~!@#$%^\u0026*()_\u002B{}|:\u0022\u003C\u003E?\u72EC\u89D2\u517D\u03C0\u7368\u89D2\u7378"'), [j].[Id] +FROM [JsonEntitiesCustomNaming] AS [j] +"""); + } + + public override async Task Custom_naming_projection_owned_collection(bool async) + { + await base.Custom_naming_projection_owned_collection(async); + + AssertSql( + """ +SELECT [j].[json_collection_custom_naming], [j].[Id] +FROM [JsonEntitiesCustomNaming] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Custom_naming_projection_owned_scalar(bool async) + { + await base.Custom_naming_projection_owned_scalar(async); + + AssertSql( + """ +SELECT CAST(JSON_VALUE([j].[json_reference_custom_naming], '$."Custom#OwnedReferenceBranch\u0060-=[]\\;\u0027,./~!@#$%^\u0026*()_\u002B{}|:\u0022\u003C\u003E?\u72EC\u89D2\u517D\u03C0\u7368\u89D2\u7378"."\u30E6\u30CB\u30B3\u30FC\u30F3Fraction\u4E00\u89D2\u7363"') AS float) +FROM [JsonEntitiesCustomNaming] AS [j] +"""); + } + + public override async Task Custom_naming_projection_everything(bool async) + { + await base.Custom_naming_projection_everything(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Title], [j].[json_collection_custom_naming], [j].[json_reference_custom_naming], [j].[json_reference_custom_naming], JSON_QUERY([j].[json_reference_custom_naming], '$."Custom#OwnedReferenceBranch\u0060-=[]\\;\u0027,./~!@#$%^\u0026*()_\u002B{}|:\u0022\u003C\u003E?\u72EC\u89D2\u517D\u03C0\u7368\u89D2\u7378"'), [j].[json_collection_custom_naming], JSON_QUERY([j].[json_reference_custom_naming], '$.CustomOwnedCollectionBranch'), JSON_VALUE([j].[json_reference_custom_naming], '$.CustomName'), CAST(JSON_VALUE([j].[json_reference_custom_naming], '$."Custom#OwnedReferenceBranch\u0060-=[]\\;\u0027,./~!@#$%^\u0026*()_\u002B{}|:\u0022\u003C\u003E?\u72EC\u89D2\u517D\u03C0\u7368\u89D2\u7378"."\u30E6\u30CB\u30B3\u30FC\u30F3Fraction\u4E00\u89D2\u7363"') AS float) +FROM [JsonEntitiesCustomNaming] AS [j] +"""); + } + + public override async Task Project_entity_with_single_owned(bool async) + { + await base.Project_entity_with_single_owned(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Name], [j].[OwnedCollection] +FROM [JsonEntitiesSingleOwned] AS [j] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Left_join_json_entities(bool async) + { + await base.Left_join_json_entities(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Name], [j].[OwnedCollection], [j0].[Id], [j0].[EntityBasicId], [j0].[Name], [j0].[OwnedCollectionRoot], [j0].[OwnedReferenceRoot] +FROM [JsonEntitiesSingleOwned] AS [j] +LEFT JOIN [JsonEntitiesBasic] AS [j0] ON [j].[Id] = [j0].[Id] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Left_join_json_entities_complex_projection(bool async) + { + await base.Left_join_json_entities_complex_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [j0].[Id], [j0].[OwnedReferenceRoot], JSON_QUERY([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), JSON_QUERY([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), JSON_QUERY([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf') +FROM [JsonEntitiesSingleOwned] AS [j] +LEFT JOIN [JsonEntitiesBasic] AS [j0] ON [j].[Id] = [j0].[Id] +"""); + } + + public override async Task Left_join_json_entities_json_being_inner(bool async) + { + await base.Left_join_json_entities_json_being_inner(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j0].[Id], [j0].[Name], [j0].[OwnedCollection] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesSingleOwned] AS [j0] ON [j].[Id] = [j0].[Id] +"""); + } + + public override async Task Left_join_json_entities_complex_projection_json_being_inner(bool async) + { + await base.Left_join_json_entities_complex_projection_json_being_inner(async); + + AssertSql( + """ +SELECT [j].[Id], [j0].[Id], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), [j0].[Name] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesSingleOwned] AS [j0] ON [j].[Id] = [j0].[Id] +"""); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery(bool async) + { + await base.Project_json_entity_FirstOrDefault_subquery(async); + + AssertSql( + """ +SELECT [j1].[c], [j1].[Id] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT TOP(1) JSON_QUERY([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch') AS [c], [j0].[Id] + FROM [JsonEntitiesBasic] AS [j0] + ORDER BY [j0].[Id] +) AS [j1] +ORDER BY [j].[Id] +"""); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery_with_binding_on_top(bool async) + { + await base.Project_json_entity_FirstOrDefault_subquery_with_binding_on_top(async); + + AssertSql( + """ +SELECT ( + SELECT TOP(1) CAST(JSON_VALUE([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch.Date') AS datetime2) + FROM [JsonEntitiesBasic] AS [j0] + ORDER BY [j0].[Id]) +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery_with_entity_comparison_on_top(bool async) + { + await base.Project_json_entity_FirstOrDefault_subquery_with_entity_comparison_on_top(async); + + AssertSql( + @""); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery_deduplication(bool async) + { + await base.Project_json_entity_FirstOrDefault_subquery_deduplication(async); + + AssertSql( + """ +SELECT [j1].[c], [j1].[Id], [j1].[c0], [j1].[Id0], [j1].[c1], [j1].[c2], [j1].[c3], [j1].[c4] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT TOP(1) JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch') AS [c], [j].[Id], [j0].[OwnedReferenceRoot] AS [c0], [j0].[Id] AS [Id0], JSON_QUERY([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch') AS [c1], JSON_VALUE([j0].[OwnedReferenceRoot], '$.Name') AS [c2], CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.Enum') AS int) AS [c3], 1 AS [c4] + FROM [JsonEntitiesBasic] AS [j0] + ORDER BY [j0].[Id] +) AS [j1] +ORDER BY [j].[Id] +"""); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery_deduplication_and_outer_reference(bool async) + { + await base.Project_json_entity_FirstOrDefault_subquery_deduplication_and_outer_reference(async); + + AssertSql( + """ +SELECT [j1].[c], [j1].[Id], [j1].[c0], [j1].[Id0], [j1].[c1], [j1].[c2], [j1].[c3], [j1].[c4] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT TOP(1) JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch') AS [c], [j].[Id], [j0].[OwnedReferenceRoot] AS [c0], [j0].[Id] AS [Id0], JSON_QUERY([j0].[OwnedReferenceRoot], '$.OwnedReferenceBranch') AS [c1], JSON_VALUE([j0].[OwnedReferenceRoot], '$.Name') AS [c2], CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.Enum') AS int) AS [c3], 1 AS [c4] + FROM [JsonEntitiesBasic] AS [j0] + ORDER BY [j0].[Id] +) AS [j1] +ORDER BY [j].[Id] +"""); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery_deduplication_outer_reference_and_pruning(bool async) + { + await base.Project_json_entity_FirstOrDefault_subquery_deduplication_outer_reference_and_pruning(async); + + AssertSql( + """ +SELECT [j1].[c], [j1].[Id], [j1].[c0] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT TOP(1) JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch') AS [c], [j].[Id], 1 AS [c0] + FROM [JsonEntitiesBasic] AS [j0] + ORDER BY [j0].[Id] +) AS [j1] +ORDER BY [j].[Id] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Json_entity_with_inheritance_basic_projection(bool async) + { + await base.Json_entity_with_inheritance_basic_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Discriminator], [j].[Name], [j].[Fraction], [j].[CollectionOnBase], [j].[ReferenceOnBase], [j].[CollectionOnDerived], [j].[ReferenceOnDerived] +FROM [JsonEntitiesInheritance] AS [j] +"""); + } + + public override async Task Json_entity_with_inheritance_project_derived(bool async) + { + await base.Json_entity_with_inheritance_project_derived(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Discriminator], [j].[Name], [j].[Fraction], [j].[CollectionOnBase], [j].[ReferenceOnBase], [j].[CollectionOnDerived], [j].[ReferenceOnDerived] +FROM [JsonEntitiesInheritance] AS [j] +WHERE [j].[Discriminator] = N'JsonEntityInheritanceDerived' +"""); + } + + public override async Task Json_entity_with_inheritance_project_navigations(bool async) + { + await base.Json_entity_with_inheritance_project_navigations(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[ReferenceOnBase], [j].[CollectionOnBase] +FROM [JsonEntitiesInheritance] AS [j] +"""); + } + + public override async Task Json_entity_with_inheritance_project_navigations_on_derived(bool async) + { + await base.Json_entity_with_inheritance_project_navigations_on_derived(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[ReferenceOnBase], [j].[ReferenceOnDerived], [j].[CollectionOnBase], [j].[CollectionOnDerived] +FROM [JsonEntitiesInheritance] AS [j] +WHERE [j].[Discriminator] = N'JsonEntityInheritanceDerived' +"""); + } + + public override async Task Json_entity_backtracking(bool async) + { + await base.Json_entity_backtracking(async); + + AssertSql( + @""); + } + + public override async Task Json_collection_index_in_projection_basic(bool async) + { + await base.Json_collection_index_in_projection_basic(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[1]'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_ElementAt_in_projection(bool async) + { + await base.Json_collection_ElementAt_in_projection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[1]'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_ElementAtOrDefault_in_projection(bool async) + { + await base.Json_collection_ElementAtOrDefault_in_projection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[1]'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_projection_project_collection(bool async) + { + await base.Json_collection_index_in_projection_project_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_ElementAt_project_collection(bool async) + { + await base.Json_collection_ElementAt_project_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_ElementAtOrDefault_project_collection(bool async) + { + await base.Json_collection_ElementAtOrDefault_project_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_using_parameter(bool async) + { + await base.Json_collection_index_in_projection_using_parameter(async); + + AssertSql( + """ +@__prm_0='0' + +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), [j].[Id], @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_using_column(bool async) + { + await base.Json_collection_index_in_projection_using_column(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + ']'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_projection_using_untranslatable_client_method(bool async) + { + var message = (await Assert.ThrowsAsync( + () => base.Json_collection_index_in_projection_using_untranslatable_client_method(async))).Message; + + Assert.Contains( + CoreStrings.QueryUnableToTranslateMethod( + "Microsoft.EntityFrameworkCore.Query.JsonQueryTestBase", + "MyMethod"), + message); + } + + public override async Task Json_collection_index_in_projection_using_untranslatable_client_method2(bool async) + { + var message = (await Assert.ThrowsAsync( + () => base.Json_collection_index_in_projection_using_untranslatable_client_method2(async))).Message; + + Assert.Contains( + CoreStrings.QueryUnableToTranslateMethod( + "Microsoft.EntityFrameworkCore.Query.JsonQueryTestBase", + "MyMethod"), + message); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Json_collection_index_outside_bounds(bool async) + { + await base.Json_collection_index_outside_bounds(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[25]'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Json_collection_index_outside_bounds2(bool async) + { + await base.Json_collection_index_outside_bounds2(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf[25]'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_outside_bounds_with_property_access(bool async) + { + await base.Json_collection_index_outside_bounds_with_property_access(async); + + AssertSql( + """ +SELECT CAST(JSON_VALUE([j].[OwnedCollectionRoot], '$[25].Number') AS int) +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_nested(bool async) + { + await base.Json_collection_index_in_projection_nested(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), [j].[Id], @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_nested_project_scalar(bool async) + { + await base.Json_collection_index_in_projection_nested_project_scalar(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT CAST(JSON_VALUE([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + '].Date') AS datetime2) +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_nested_project_reference(bool async) + { + await base.Json_collection_index_in_projection_nested_project_reference(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedReferenceLeaf'), [j].[Id], @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_nested_project_collection(bool async) + { + await base.Json_collection_index_in_projection_nested_project_collection(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionLeaf'), [j].[Id], @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_nested_project_collection_anonymous_projection(bool async) + { + await base.Json_collection_index_in_projection_nested_project_collection_anonymous_projection(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionLeaf'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_predicate_using_constant(bool async) + { + await base.Json_collection_index_in_predicate_using_constant(async); + + AssertSql( + """ +SELECT [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[0].Name') <> N'Foo' OR JSON_VALUE([j].[OwnedCollectionRoot], '$[0].Name') IS NULL +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_predicate_using_variable(bool async) + { + await base.Json_collection_index_in_predicate_using_variable(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].Name') <> N'Foo' OR JSON_VALUE([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].Name') IS NULL +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_predicate_using_column(bool async) + { + await base.Json_collection_index_in_predicate_using_column(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].Name') = N'e1_c2' +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_predicate_using_complex_expression1(bool async) + { + await base.Json_collection_index_in_predicate_using_complex_expression1(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[' + CAST(CASE + WHEN [j].[Id] = 1 THEN 0 + ELSE 1 +END AS nvarchar(max)) + '].Name') = N'e1_c1' +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_predicate_using_complex_expression2(bool async) + { + await base.Json_collection_index_in_predicate_using_complex_expression2(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[' + CAST(( + SELECT MAX([j0].[Id]) + FROM [JsonEntitiesBasic] AS [j0]) AS nvarchar(max)) + '].Name') = N'e1_c2' +"""); + } + + public override async Task Json_collection_ElementAt_in_predicate(bool async) + { + await base.Json_collection_ElementAt_in_predicate(async); + + AssertSql( + """ +SELECT [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[1].Name') <> N'Foo' OR JSON_VALUE([j].[OwnedCollectionRoot], '$[1].Name') IS NULL +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_predicate_nested_mix(bool async) + { + await base.Json_collection_index_in_predicate_nested_mix(async); + + AssertSql( + """ +@__prm_0='0' + +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionLeaf[' + CAST([j].[Id] - 1 AS nvarchar(max)) + '].SomethingSomething') = N'e1_c2_c1_c1' +"""); + } + + public override async Task Json_collection_ElementAt_and_pushdown(bool async) + { + await base.Json_collection_ElementAt_and_pushdown(async); + + AssertSql( + """ +SELECT [j].[Id], CAST(JSON_VALUE([j].[OwnedCollectionRoot], '$[0].Number') AS int) AS [CollectionElement] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_Any_with_predicate(bool async) + { + await base.Json_collection_Any_with_predicate(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') WITH ([OwnedReferenceLeaf] nvarchar(max) '$.OwnedReferenceLeaf' AS JSON) AS [o] + WHERE JSON_VALUE([o].[OwnedReferenceLeaf], '$.SomethingSomething') = N'e1_r_c1_r') +"""); + } + + public override async Task Json_collection_Where_ElementAt(bool async) + { + await base.Json_collection_Where_ElementAt(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE ( + SELECT JSON_VALUE([o].[value], '$.OwnedReferenceLeaf.SomethingSomething') + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') AS [o] + WHERE CAST(JSON_VALUE([o].[value], '$.Enum') AS int) = -3 + ORDER BY CAST([o].[key] AS int) + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) = N'e1_r_c2_r' +"""); + } + + public override async Task Json_collection_Skip(bool async) + { + await base.Json_collection_Skip(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE ( + SELECT [o0].[c] + FROM ( + SELECT JSON_VALUE([o].[value], '$.OwnedReferenceLeaf.SomethingSomething') AS [c], CAST([o].[key] AS int) AS [c0] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') AS [o] + ORDER BY CAST([o].[key] AS int) + OFFSET 1 ROWS + ) AS [o0] + ORDER BY [o0].[c0] + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) = N'e1_r_c2_r' +"""); + } + + public override async Task Json_collection_OrderByDescending_Skip_ElementAt(bool async) + { + await base.Json_collection_OrderByDescending_Skip_ElementAt(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE ( + SELECT [o0].[c] + FROM ( + SELECT JSON_VALUE([o].[OwnedReferenceLeaf], '$.SomethingSomething') AS [c], [o].[Date] AS [c0] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') WITH ( + [Date] datetime2 '$.Date', + [Enum] int '$.Enum', + [Fraction] decimal(18,2) '$.Fraction', + [OwnedReferenceLeaf] nvarchar(max) '$.OwnedReferenceLeaf' AS JSON + ) AS [o] + ORDER BY [o].[Date] DESC + OFFSET 1 ROWS + ) AS [o0] + ORDER BY [o0].[c0] DESC + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) = N'e1_r_c1_r' +"""); + } + + public override async Task Json_collection_Distinct_Count_with_predicate(bool async) + { + await base.Json_collection_Distinct_Count_with_predicate(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT DISTINCT [j].[Id], [o].[Date], [o].[Enum], [o].[Enums], [o].[Fraction], [o].[NullableEnum], [o].[NullableEnums], [o].[OwnedCollectionLeaf] AS [c], [o].[OwnedReferenceLeaf] AS [c0] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') WITH ( + [Date] datetime2 '$.Date', + [Enum] int '$.Enum', + [Enums] nvarchar(max) '$.Enums' AS JSON, + [Fraction] decimal(18,2) '$.Fraction', + [NullableEnum] int '$.NullableEnum', + [NullableEnums] nvarchar(max) '$.NullableEnums' AS JSON, + [OwnedCollectionLeaf] nvarchar(max) '$.OwnedCollectionLeaf' AS JSON, + [OwnedReferenceLeaf] nvarchar(max) '$.OwnedReferenceLeaf' AS JSON + ) AS [o] + WHERE JSON_VALUE([o].[OwnedReferenceLeaf], '$.SomethingSomething') = N'e1_r_c2_r' + ) AS [o0]) = 1 +"""); + } + + public override async Task Json_collection_within_collection_Count(bool async) + { + await base.Json_collection_within_collection_Count(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') WITH ([OwnedCollectionBranch] nvarchar(max) '$.OwnedCollectionBranch' AS JSON) AS [o] + WHERE ( + SELECT COUNT(*) + FROM OPENJSON(CAST([o].[OwnedCollectionBranch] AS nvarchar(max)), '$') AS [o0]) = 2) +"""); + } + + public override async Task Json_collection_in_projection_with_composition_count(bool async) + { + await base.Json_collection_in_projection_with_composition_count(async); + + AssertSql( + """ +SELECT ( + SELECT COUNT(*) + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o]) +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_collection_in_projection_with_anonymous_projection_of_scalars(bool async) + { + await base.Json_collection_in_projection_with_anonymous_projection_of_scalars(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_VALUE([o].[value], '$.Name'), CAST(JSON_VALUE([o].[value], '$.Number') AS int), [o].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] +ORDER BY [j].[Id], CAST([o].[key] AS int) +"""); + } + + public override async Task Json_collection_in_projection_with_composition_where_and_anonymous_projection_of_scalars(bool async) + { + await base.Json_collection_in_projection_with_composition_where_and_anonymous_projection_of_scalars(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Name], [o0].[Number], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT JSON_VALUE([o].[value], '$.Name') AS [Name], CAST(JSON_VALUE([o].[value], '$.Number') AS int) AS [Number], [o].[key], CAST([o].[key] AS int) AS [c] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + WHERE JSON_VALUE([o].[value], '$.Name') = N'Foo' +) AS [o0] +ORDER BY [j].[Id], [o0].[c] +"""); + } + + public override async Task Json_collection_in_projection_with_composition_where_and_anonymous_projection_of_primitive_arrays(bool async) + { + await base.Json_collection_in_projection_with_composition_where_and_anonymous_projection_of_primitive_arrays(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Names], [o0].[Numbers], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT JSON_QUERY([o].[value], '$.Names') AS [Names], JSON_QUERY([o].[value], '$.Numbers') AS [Numbers], [o].[key], CAST([o].[key] AS int) AS [c] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + WHERE JSON_VALUE([o].[value], '$.Name') = N'Foo' +) AS [o0] +ORDER BY [j].[Id], [o0].[c] +"""); + } + + public override async Task Json_collection_filter_in_projection(bool async) + { + await base.Json_collection_filter_in_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Id], [o0].[Name], [o0].[Names], [o0].[Number], [o0].[Numbers], [o0].[c], [o0].[c0], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [j].[Id], JSON_VALUE([o].[value], '$.Name') AS [Name], JSON_QUERY([o].[value], '$.Names') AS [Names], CAST(JSON_VALUE([o].[value], '$.Number') AS int) AS [Number], JSON_QUERY([o].[value], '$.Numbers') AS [Numbers], JSON_QUERY([o].[value], '$.OwnedCollectionBranch') AS [c], JSON_QUERY([o].[value], '$.OwnedReferenceBranch') AS [c0], [o].[key], CAST([o].[key] AS int) AS [c1] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + WHERE JSON_VALUE([o].[value], '$.Name') <> N'Foo' OR JSON_VALUE([o].[value], '$.Name') IS NULL +) AS [o0] +ORDER BY [j].[Id], [o0].[c1] +"""); + } + + public override async Task Json_nested_collection_filter_in_projection(bool async) + { + await base.Json_nested_collection_filter_in_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [s].[key], [s].[Id], [s].[Date], [s].[Enum], [s].[Enums], [s].[Fraction], [s].[NullableEnum], [s].[NullableEnums], [s].[c], [s].[c0], [s].[key0] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [o].[key], [o1].[Id], [o1].[Date], [o1].[Enum], [o1].[Enums], [o1].[Fraction], [o1].[NullableEnum], [o1].[NullableEnums], [o1].[c], [o1].[c0], [o1].[key] AS [key0], CAST([o].[key] AS int) AS [c1], [o1].[c1] AS [c10] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + OUTER APPLY ( + SELECT [j].[Id], CAST(JSON_VALUE([o0].[value], '$.Date') AS datetime2) AS [Date], CAST(JSON_VALUE([o0].[value], '$.Enum') AS int) AS [Enum], JSON_QUERY([o0].[value], '$.Enums') AS [Enums], CAST(JSON_VALUE([o0].[value], '$.Fraction') AS decimal(18,2)) AS [Fraction], CAST(JSON_VALUE([o0].[value], '$.NullableEnum') AS int) AS [NullableEnum], JSON_QUERY([o0].[value], '$.NullableEnums') AS [NullableEnums], JSON_QUERY([o0].[value], '$.OwnedCollectionLeaf') AS [c], JSON_QUERY([o0].[value], '$.OwnedReferenceLeaf') AS [c0], [o0].[key], CAST([o0].[key] AS int) AS [c1] + FROM OPENJSON(CAST(JSON_QUERY([o].[value], '$.OwnedCollectionBranch') AS nvarchar(max)), '$') AS [o0] + WHERE CAST(JSON_VALUE([o0].[value], '$.Date') AS datetime2) <> '2000-01-01T00:00:00.0000000' + ) AS [o1] +) AS [s] +ORDER BY [j].[Id], [s].[c1], [s].[key], [s].[c10] +"""); + } + + public override async Task Json_nested_collection_anonymous_projection_in_projection(bool async) + { + await base.Json_nested_collection_anonymous_projection_in_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [s].[key], [s].[c], [s].[c0], [s].[c1], [s].[c2], [s].[c3], [s].[Id], [s].[c4], [s].[key0] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [o].[key], CAST(JSON_VALUE([o0].[value], '$.Date') AS datetime2) AS [c], CAST(JSON_VALUE([o0].[value], '$.Enum') AS int) AS [c0], JSON_QUERY([o0].[value], '$.Enums') AS [c1], CAST(JSON_VALUE([o0].[value], '$.Fraction') AS decimal(18,2)) AS [c2], JSON_QUERY([o0].[value], '$.OwnedReferenceLeaf') AS [c3], [j].[Id], JSON_QUERY([o0].[value], '$.OwnedCollectionLeaf') AS [c4], [o0].[key] AS [key0], CAST([o].[key] AS int) AS [c5], CAST([o0].[key] AS int) AS [c6] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + OUTER APPLY OPENJSON(CAST(JSON_QUERY([o].[value], '$.OwnedCollectionBranch') AS nvarchar(max)), '$') AS [o0] +) AS [s] +ORDER BY [j].[Id], [s].[c5], [s].[key], [s].[c6] +"""); + } + + public override async Task Json_collection_skip_take_in_projection(bool async) + { + await base.Json_collection_skip_take_in_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Id], [o0].[Name], [o0].[Names], [o0].[Number], [o0].[Numbers], [o0].[c], [o0].[c0], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [j].[Id], JSON_VALUE([o].[value], '$.Name') AS [Name], JSON_QUERY([o].[value], '$.Names') AS [Names], CAST(JSON_VALUE([o].[value], '$.Number') AS int) AS [Number], JSON_QUERY([o].[value], '$.Numbers') AS [Numbers], JSON_QUERY([o].[value], '$.OwnedCollectionBranch') AS [c], JSON_QUERY([o].[value], '$.OwnedReferenceBranch') AS [c0], [o].[key], JSON_VALUE([o].[value], '$.Name') AS [c1] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + ORDER BY JSON_VALUE([o].[value], '$.Name') + OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY +) AS [o0] +ORDER BY [j].[Id], [o0].[c1] +"""); + } + + public override async Task Json_collection_skip_take_in_projection_project_into_anonymous_type(bool async) + { + await base.Json_collection_skip_take_in_projection_project_into_anonymous_type(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[c], [o0].[c0], [o0].[c1], [o0].[c2], [o0].[c3], [o0].[Id], [o0].[c4], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT JSON_VALUE([o].[value], '$.Name') AS [c], JSON_QUERY([o].[value], '$.Names') AS [c0], CAST(JSON_VALUE([o].[value], '$.Number') AS int) AS [c1], JSON_QUERY([o].[value], '$.Numbers') AS [c2], JSON_QUERY([o].[value], '$.OwnedCollectionBranch') AS [c3], [j].[Id], JSON_QUERY([o].[value], '$.OwnedReferenceBranch') AS [c4], [o].[key] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + ORDER BY JSON_VALUE([o].[value], '$.Name') + OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY +) AS [o0] +ORDER BY [j].[Id], [o0].[c] +"""); + } + + public override async Task Json_collection_skip_take_in_projection_with_json_reference_access_as_final_operation(bool async) + { + await base.Json_collection_skip_take_in_projection_with_json_reference_access_as_final_operation(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[c], [o0].[Id], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT JSON_QUERY([o].[value], '$.OwnedReferenceBranch') AS [c], [j].[Id], [o].[key], JSON_VALUE([o].[value], '$.Name') AS [c0] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + ORDER BY JSON_VALUE([o].[value], '$.Name') + OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY +) AS [o0] +ORDER BY [j].[Id], [o0].[c0] +"""); + } + + public override async Task Json_collection_distinct_in_projection(bool async) + { + await base.Json_collection_distinct_in_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Id], [o0].[Name], [o0].[Names], [o0].[Number], [o0].[Numbers], [o0].[c], [o0].[c0] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT DISTINCT [j].[Id], [o].[Name], [o].[Names], [o].[Number], [o].[Numbers], [o].[OwnedCollectionBranch] AS [c], [o].[OwnedReferenceBranch] AS [c0] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') WITH ( + [Name] nvarchar(max) '$.Name', + [Names] nvarchar(max) '$.Names' AS JSON, + [Number] int '$.Number', + [Numbers] nvarchar(max) '$.Numbers' AS JSON, + [OwnedCollectionBranch] nvarchar(max) '$.OwnedCollectionBranch' AS JSON, + [OwnedReferenceBranch] nvarchar(max) '$.OwnedReferenceBranch' AS JSON + ) AS [o] +) AS [o0] +ORDER BY [j].[Id], [o0].[Name], [o0].[Names], [o0].[Number] +"""); + } + + public override async Task Json_collection_anonymous_projection_distinct_in_projection(bool async) + { + await base.Json_collection_anonymous_projection_distinct_in_projection(async); + + AssertSql(""); + } + + public override async Task Json_collection_leaf_filter_in_projection(bool async) + { + await base.Json_collection_leaf_filter_in_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Id], [o0].[SomethingSomething], [o0].[key] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [j].[Id], JSON_VALUE([o].[value], '$.SomethingSomething') AS [SomethingSomething], [o].[key], CAST([o].[key] AS int) AS [c] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedReferenceBranch.OwnedCollectionLeaf') AS [o] + WHERE JSON_VALUE([o].[value], '$.SomethingSomething') <> N'Baz' OR JSON_VALUE([o].[value], '$.SomethingSomething') IS NULL +) AS [o0] +ORDER BY [j].[Id], [o0].[c] +"""); + } + + public override async Task Json_multiple_collection_projections(bool async) + { + await base.Json_multiple_collection_projections(async); + + AssertSql( + """ +SELECT [j].[Id], [o4].[Id], [o4].[SomethingSomething], [o4].[key], [o1].[Id], [o1].[Name], [o1].[Names], [o1].[Number], [o1].[Numbers], [o1].[c], [o1].[c0], [s].[key], [s].[Id], [s].[Date], [s].[Enum], [s].[Enums], [s].[Fraction], [s].[NullableEnum], [s].[NullableEnums], [s].[c], [s].[c0], [s].[key0], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [j].[Id], JSON_VALUE([o].[value], '$.SomethingSomething') AS [SomethingSomething], [o].[key], CAST([o].[key] AS int) AS [c] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedReferenceBranch.OwnedCollectionLeaf') AS [o] + WHERE JSON_VALUE([o].[value], '$.SomethingSomething') <> N'Baz' OR JSON_VALUE([o].[value], '$.SomethingSomething') IS NULL +) AS [o4] +OUTER APPLY ( + SELECT DISTINCT [j].[Id], [o0].[Name], [o0].[Names], [o0].[Number], [o0].[Numbers], [o0].[OwnedCollectionBranch] AS [c], [o0].[OwnedReferenceBranch] AS [c0] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') WITH ( + [Name] nvarchar(max) '$.Name', + [Names] nvarchar(max) '$.Names' AS JSON, + [Number] int '$.Number', + [Numbers] nvarchar(max) '$.Numbers' AS JSON, + [OwnedCollectionBranch] nvarchar(max) '$.OwnedCollectionBranch' AS JSON, + [OwnedReferenceBranch] nvarchar(max) '$.OwnedReferenceBranch' AS JSON + ) AS [o0] +) AS [o1] +OUTER APPLY ( + SELECT [o2].[key], [o5].[Id], [o5].[Date], [o5].[Enum], [o5].[Enums], [o5].[Fraction], [o5].[NullableEnum], [o5].[NullableEnums], [o5].[c], [o5].[c0], [o5].[key] AS [key0], CAST([o2].[key] AS int) AS [c1], [o5].[c1] AS [c10] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o2] + OUTER APPLY ( + SELECT [j].[Id], CAST(JSON_VALUE([o3].[value], '$.Date') AS datetime2) AS [Date], CAST(JSON_VALUE([o3].[value], '$.Enum') AS int) AS [Enum], JSON_QUERY([o3].[value], '$.Enums') AS [Enums], CAST(JSON_VALUE([o3].[value], '$.Fraction') AS decimal(18,2)) AS [Fraction], CAST(JSON_VALUE([o3].[value], '$.NullableEnum') AS int) AS [NullableEnum], JSON_QUERY([o3].[value], '$.NullableEnums') AS [NullableEnums], JSON_QUERY([o3].[value], '$.OwnedCollectionLeaf') AS [c], JSON_QUERY([o3].[value], '$.OwnedReferenceLeaf') AS [c0], [o3].[key], CAST([o3].[key] AS int) AS [c1] + FROM OPENJSON(CAST(JSON_QUERY([o2].[value], '$.OwnedCollectionBranch') AS nvarchar(max)), '$') AS [o3] + WHERE CAST(JSON_VALUE([o3].[value], '$.Date') AS datetime2) <> '2000-01-01T00:00:00.0000000' + ) AS [o5] +) AS [s] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id], [o4].[c], [o4].[key], [o1].[Name], [o1].[Names], [o1].[Number], [o1].[Numbers], [s].[c1], [s].[key], [s].[c10], [s].[key0] +"""); + } + + public override async Task Json_branch_collection_distinct_and_other_collection(bool async) + { + await base.Json_branch_collection_distinct_and_other_collection(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Id], [o0].[Date], [o0].[Enum], [o0].[Enums], [o0].[Fraction], [o0].[NullableEnum], [o0].[NullableEnums], [o0].[c], [o0].[c0], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT DISTINCT [j].[Id], [o].[Date], [o].[Enum], [o].[Enums], [o].[Fraction], [o].[NullableEnum], [o].[NullableEnums], [o].[OwnedCollectionLeaf] AS [c], [o].[OwnedReferenceLeaf] AS [c0] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') WITH ( + [Date] datetime2 '$.Date', + [Enum] int '$.Enum', + [Enums] nvarchar(max) '$.Enums' AS JSON, + [Fraction] decimal(18,2) '$.Fraction', + [NullableEnum] int '$.NullableEnum', + [NullableEnums] nvarchar(max) '$.NullableEnums' AS JSON, + [OwnedCollectionLeaf] nvarchar(max) '$.OwnedCollectionLeaf' AS JSON, + [OwnedReferenceLeaf] nvarchar(max) '$.OwnedReferenceLeaf' AS JSON + ) AS [o] +) AS [o0] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id], [o0].[Date], [o0].[Enum], [o0].[Enums], [o0].[Fraction], [o0].[NullableEnum], [o0].[NullableEnums] +"""); + } + + public override async Task Json_leaf_collection_distinct_and_other_collection(bool async) + { + await base.Json_leaf_collection_distinct_and_other_collection(async); + + AssertSql( + """ +SELECT [j].[Id], [o0].[Id], [o0].[SomethingSomething], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT DISTINCT [j].[Id], [o].[SomethingSomething] + FROM OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedReferenceBranch.OwnedCollectionLeaf') WITH ([SomethingSomething] nvarchar(max) '$.SomethingSomething') AS [o] +) AS [o0] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id], [o0].[SomethingSomething] +"""); + } + + public override async Task Json_collection_SelectMany(bool async) + { + await base.Json_collection_SelectMany(async); + + AssertSql( + """ +SELECT [j].[Id], [o].[Name], [o].[Names], [o].[Number], [o].[Numbers], [o].[OwnedCollectionBranch], [o].[OwnedReferenceBranch] +FROM [JsonEntitiesBasic] AS [j] +CROSS APPLY OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') WITH ( + [Name] nvarchar(max) '$.Name', + [Names] nvarchar(max) '$.Names' AS JSON, + [Number] int '$.Number', + [Numbers] nvarchar(max) '$.Numbers' AS JSON, + [OwnedCollectionBranch] nvarchar(max) '$.OwnedCollectionBranch' AS JSON, + [OwnedReferenceBranch] nvarchar(max) '$.OwnedReferenceBranch' AS JSON +) AS [o] +"""); + } + + public override async Task Json_nested_collection_SelectMany(bool async) + { + await base.Json_nested_collection_SelectMany(async); + + AssertSql( + """ +SELECT [j].[Id], [o].[Date], [o].[Enum], [o].[Enums], [o].[Fraction], [o].[NullableEnum], [o].[NullableEnums], [o].[OwnedCollectionLeaf], [o].[OwnedReferenceLeaf] +FROM [JsonEntitiesBasic] AS [j] +CROSS APPLY OPENJSON(CAST([j].[OwnedReferenceRoot] AS nvarchar(max)), '$.OwnedCollectionBranch') WITH ( + [Date] datetime2 '$.Date', + [Enum] int '$.Enum', + [Enums] nvarchar(max) '$.Enums' AS JSON, + [Fraction] decimal(18,2) '$.Fraction', + [NullableEnum] int '$.NullableEnum', + [NullableEnums] nvarchar(max) '$.NullableEnums' AS JSON, + [OwnedCollectionLeaf] nvarchar(max) '$.OwnedCollectionLeaf' AS JSON, + [OwnedReferenceLeaf] nvarchar(max) '$.OwnedReferenceLeaf' AS JSON +) AS [o] +"""); + } + + public override async Task Json_collection_of_primitives_SelectMany(bool async) + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "OpenJson support not yet supported for JSON native data type.", + (await Assert.ThrowsAsync( + () => base.Json_collection_of_primitives_SelectMany(async))).Message); + + AssertSql( + """ +SELECT [n].[value] +FROM [JsonEntitiesBasic] AS [j] +CROSS APPLY OPENJSON(JSON_QUERY([j].[OwnedReferenceRoot], '$.Names')) WITH ([value] nvarchar(max) '$') AS [n] +"""); + } + + public override async Task Json_collection_of_primitives_index_used_in_predicate(bool async) + { + await base.Json_collection_of_primitives_index_used_in_predicate(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE JSON_VALUE([j].[OwnedReferenceRoot], '$.Names[0]') = N'e1_r1' +"""); + } + + public override async Task Json_collection_of_primitives_index_used_in_projection(bool async) + { + await base.Json_collection_of_primitives_index_used_in_projection(async); + + AssertSql( + """ +SELECT CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.Enums[0]') AS int) +FROM [JsonEntitiesBasic] AS [j] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_collection_of_primitives_index_used_in_orderby(bool async) + { + await base.Json_collection_of_primitives_index_used_in_orderby(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +ORDER BY CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.Numbers[0]') AS int) +"""); + } + + public override async Task Json_collection_of_primitives_contains_in_predicate(bool async) + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "OpenJson support not yet supported for JSON native data type.", + (await Assert.ThrowsAsync( + () => base.Json_collection_of_primitives_contains_in_predicate(async))).Message); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +WHERE N'e1_r1' IN ( + SELECT [n].[value] + FROM OPENJSON(JSON_QUERY([j].[OwnedReferenceRoot], '$.Names')) WITH ([value] nvarchar(max) '$') AS [n] +) +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_with_parameter_Select_ElementAt(bool async) + { + await base.Json_collection_index_with_parameter_Select_ElementAt(async); + + AssertSql( + """ +@__prm_0='0' + +SELECT [j].[Id], ( + SELECT N'Foo' + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch') AS [o] + ORDER BY CAST([o].[key] AS int) + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) AS [CollectionElement] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_with_expression_Select_ElementAt(bool async) + { + await base.Json_collection_index_with_expression_Select_ElementAt(async); + + AssertSql( + """ +@__prm_0='0' + +SELECT JSON_VALUE([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 + [j].[Id] AS nvarchar(max)) + '].OwnedCollectionBranch[0].OwnedReferenceLeaf.SomethingSomething') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_Select_entity_collection_ElementAt(bool async) + { + await base.Json_collection_Select_entity_collection_ElementAt(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_Select_entity_ElementAt(bool async) + { + await base.Json_collection_Select_entity_ElementAt(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedReferenceBranch'), [j].[Id] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_Select_entity_in_anonymous_object_ElementAt(bool async) + { + await base.Json_collection_Select_entity_in_anonymous_object_ElementAt(async); + + AssertSql( + """ +SELECT [o0].[c], [o0].[Id], [o0].[c0] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT JSON_QUERY([o].[value], '$.OwnedReferenceBranch') AS [c], [j].[Id], 1 AS [c0] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + ORDER BY CAST([o].[key] AS int) + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY +) AS [o0] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_collection_Select_entity_with_initializer_ElementAt(bool async) + { + await base.Json_collection_Select_entity_with_initializer_ElementAt(async); + + AssertSql( + """ +SELECT [o0].[Id], [o0].[c] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [j].[Id], 1 AS [c] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + ORDER BY CAST([o].[key] AS int) + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY +) AS [o0] +"""); + } + + public override async Task Json_projection_deduplication_with_collection_indexer_in_original(bool async) + { + await base.Json_projection_deduplication_with_collection_indexer_in_original(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[0]'), JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedReferenceBranch.OwnedCollectionLeaf') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_projection_deduplication_with_collection_indexer_in_target(bool async) + { + await base.Json_projection_deduplication_with_collection_indexer_in_target(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[1]'), [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_projection_deduplication_with_collection_in_original_and_collection_indexer_in_target(bool async) + { + await base.Json_projection_deduplication_with_collection_in_original_and_collection_indexer_in_target(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), [j].[Id], @__prm_0, JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_projection_using_constant_when_owner_is_present(bool async) + { + await base.Json_collection_index_in_projection_using_constant_when_owner_is_present(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_projection_using_constant_when_owner_is_not_present(bool async) + { + await base.Json_collection_index_in_projection_using_constant_when_owner_is_not_present(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_using_parameter_when_owner_is_present(bool async) + { + await base.Json_collection_index_in_projection_using_parameter_when_owner_is_present(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_using_parameter_when_owner_is_not_present(bool async) + { + await base.Json_collection_index_in_projection_using_parameter_when_owner_is_not_present(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_after_collection_index_in_projection_using_constant_when_owner_is_present(bool async) + { + await base.Json_collection_after_collection_index_in_projection_using_constant_when_owner_is_present(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_after_collection_index_in_projection_using_constant_when_owner_is_not_present(bool async) + { + await base.Json_collection_after_collection_index_in_projection_using_constant_when_owner_is_not_present(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_after_collection_index_in_projection_using_parameter_when_owner_is_present(bool async) + { + await base.Json_collection_after_collection_index_in_projection_using_parameter_when_owner_is_present(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_after_collection_index_in_projection_using_parameter_when_owner_is_not_present(bool async) + { + await base.Json_collection_after_collection_index_in_projection_using_parameter_when_owner_is_not_present(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_when_owner_is_present_misc1(bool async) + { + await base.Json_collection_index_in_projection_when_owner_is_present_misc1(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_when_owner_is_not_present_misc1(bool async) + { + await base.Json_collection_index_in_projection_when_owner_is_not_present_misc1(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_projection_when_owner_is_present_misc2(bool async) + { + await base.Json_collection_index_in_projection_when_owner_is_present_misc2(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_collection_index_in_projection_when_owner_is_not_present_misc2(bool async) + { + await base.Json_collection_index_in_projection_when_owner_is_not_present_misc2(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_when_owner_is_present_multiple(bool async) + { + await base.Json_collection_index_in_projection_when_owner_is_present_multiple(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch[1]'), @__prm_0, JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch[1].OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch[' + CAST([j].[Id] AS nvarchar(max)) + ']'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].OwnedCollectionBranch[1].OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].OwnedCollectionBranch[' + CAST([j].[Id] AS nvarchar(max)) + ']') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_collection_index_in_projection_when_owner_is_not_present_multiple(bool async) + { + await base.Json_collection_index_in_projection_when_owner_is_not_present_multiple(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch[1]'), @__prm_0, JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedCollectionBranch[1].OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionBranch[' + CAST([j].[Id] AS nvarchar(max)) + ']'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].OwnedCollectionBranch[1].OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[' + CAST([j].[Id] AS nvarchar(max)) + '].OwnedCollectionBranch[' + CAST([j].[Id] AS nvarchar(max)) + ']') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_scalar_required_null_semantics(bool async) + { + await base.Json_scalar_required_null_semantics(async); + + AssertSql( + """ +SELECT [j].[Name] +FROM [JsonEntitiesBasic] AS [j] +WHERE CAST(JSON_VALUE([j].[OwnedReferenceRoot], '$.Number') AS int) <> CAST(LEN(JSON_VALUE([j].[OwnedReferenceRoot], '$.Name')) AS int) OR JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') IS NULL +"""); + } + + public override async Task Json_scalar_optional_null_semantics(bool async) + { + await base.Json_scalar_optional_null_semantics(async); + + AssertSql( + """ +SELECT [j].[Name] +FROM [JsonEntitiesBasic] AS [j] +WHERE (JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') <> JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') OR JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') IS NULL OR JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') IS NULL) AND (JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') IS NOT NULL OR JSON_VALUE([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') IS NOT NULL) +"""); + } + + public override async Task Group_by_on_json_scalar(bool async) + { + await base.Group_by_on_json_scalar(async); + + AssertSql( + """ +SELECT [j0].[Key], COUNT(*) AS [Count] +FROM ( + SELECT JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j] +) AS [j0] +GROUP BY [j0].[Key] +"""); + } + + public override async Task Group_by_on_json_scalar_using_collection_indexer(bool async) + { + await base.Group_by_on_json_scalar_using_collection_indexer(async); + + AssertSql( + """ +SELECT [j0].[Key], COUNT(*) AS [Count] +FROM ( + SELECT JSON_VALUE([j].[OwnedCollectionRoot], '$[0].Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j] +) AS [j0] +GROUP BY [j0].[Key] +"""); + } + + public override async Task Group_by_First_on_json_scalar(bool async) + { + await base.Group_by_First_on_json_scalar(async); + + AssertSql( + """ +SELECT [j5].[Id], [j5].[EntityBasicId], [j5].[Name], [j5].[c], [j5].[c0] +FROM ( + SELECT [j0].[Key] + FROM ( + SELECT JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j] + ) AS [j0] + GROUP BY [j0].[Key] +) AS [j3] +LEFT JOIN ( + SELECT [j4].[Id], [j4].[EntityBasicId], [j4].[Name], [j4].[c] AS [c], [j4].[c0] AS [c0], [j4].[Key] + FROM ( + SELECT [j1].[Id], [j1].[EntityBasicId], [j1].[Name], [j1].[c] AS [c], [j1].[c0] AS [c0], [j1].[Key], ROW_NUMBER() OVER(PARTITION BY [j1].[Key] ORDER BY [j1].[Id]) AS [row] + FROM ( + SELECT [j2].[Id], [j2].[EntityBasicId], [j2].[Name], [j2].[OwnedCollectionRoot] AS [c], [j2].[OwnedReferenceRoot] AS [c0], JSON_VALUE([j2].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j2] + ) AS [j1] + ) AS [j4] + WHERE [j4].[row] <= 1 +) AS [j5] ON [j3].[Key] = [j5].[Key] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Group_by_FirstOrDefault_on_json_scalar(bool async) + { + await base.Group_by_FirstOrDefault_on_json_scalar(async); + + AssertSql( + """ +SELECT [j5].[Id], [j5].[EntityBasicId], [j5].[Name], [j5].[c], [j5].[c0] +FROM ( + SELECT [j0].[Key] + FROM ( + SELECT JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j] + ) AS [j0] + GROUP BY [j0].[Key] +) AS [j3] +LEFT JOIN ( + SELECT [j4].[Id], [j4].[EntityBasicId], [j4].[Name], [j4].[c] AS [c], [j4].[c0] AS [c0], [j4].[Key] + FROM ( + SELECT [j1].[Id], [j1].[EntityBasicId], [j1].[Name], [j1].[c] AS [c], [j1].[c0] AS [c0], [j1].[Key], ROW_NUMBER() OVER(PARTITION BY [j1].[Key] ORDER BY [j1].[Id]) AS [row] + FROM ( + SELECT [j2].[Id], [j2].[EntityBasicId], [j2].[Name], [j2].[OwnedCollectionRoot] AS [c], [j2].[OwnedReferenceRoot] AS [c0], JSON_VALUE([j2].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j2] + ) AS [j1] + ) AS [j4] + WHERE [j4].[row] <= 1 +) AS [j5] ON [j3].[Key] = [j5].[Key] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task Group_by_Skip_Take_on_json_scalar(bool async) + { + await base.Group_by_Skip_Take_on_json_scalar(async); + + AssertSql( + """ +SELECT [j3].[Key], [j5].[Id], [j5].[EntityBasicId], [j5].[Name], [j5].[c], [j5].[c0] +FROM ( + SELECT [j0].[Key] + FROM ( + SELECT JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j] + ) AS [j0] + GROUP BY [j0].[Key] +) AS [j3] +LEFT JOIN ( + SELECT [j4].[Id], [j4].[EntityBasicId], [j4].[Name], [j4].[c], [j4].[c0], [j4].[Key] + FROM ( + SELECT [j1].[Id], [j1].[EntityBasicId], [j1].[Name], [j1].[c] AS [c], [j1].[c0] AS [c0], [j1].[Key], ROW_NUMBER() OVER(PARTITION BY [j1].[Key] ORDER BY [j1].[Id]) AS [row] + FROM ( + SELECT [j2].[Id], [j2].[EntityBasicId], [j2].[Name], [j2].[OwnedCollectionRoot] AS [c], [j2].[OwnedReferenceRoot] AS [c0], JSON_VALUE([j2].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j2] + ) AS [j1] + ) AS [j4] + WHERE 1 < [j4].[row] AND [j4].[row] <= 6 +) AS [j5] ON [j3].[Key] = [j5].[Key] +ORDER BY [j3].[Key], [j5].[Key], [j5].[Id] +"""); + } + + public override async Task Group_by_json_scalar_Orderby_json_scalar_FirstOrDefault(bool async) + { + await base.Group_by_json_scalar_Orderby_json_scalar_FirstOrDefault(async); + + AssertSql( + @""); + } + + public override async Task Group_by_json_scalar_Skip_First_project_json_scalar(bool async) + { + await base.Group_by_json_scalar_Skip_First_project_json_scalar(async); + + AssertSql( + """ +SELECT ( + SELECT TOP(1) CAST(JSON_VALUE([j1].[c0], '$.OwnedReferenceBranch.Enum') AS int) + FROM ( + SELECT [j2].[OwnedReferenceRoot] AS [c0], JSON_VALUE([j2].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j2] + ) AS [j1] + WHERE [j0].[Key] = [j1].[Key] OR ([j0].[Key] IS NULL AND [j1].[Key] IS NULL)) +FROM ( + SELECT JSON_VALUE([j].[OwnedReferenceRoot], '$.Name') AS [Key] + FROM [JsonEntitiesBasic] AS [j] +) AS [j0] +GROUP BY [j0].[Key] +"""); + } + + public override async Task Json_with_include_on_json_entity(bool async) + { + await base.Json_with_include_on_json_entity(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_with_include_on_entity_reference(bool async) + { + await base.Json_with_include_on_entity_reference(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId] +"""); + } + + public override async Task Json_with_include_on_entity_collection(bool async) + { + await base.Json_with_include_on_entity_collection(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id] +"""); + } + + public override async Task Entity_including_collection_with_json(bool async) + { + await base.Entity_including_collection_with_json(async); + + AssertSql( + """ +SELECT [e].[Id], [e].[Name], [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [EntitiesBasic] AS [e] +LEFT JOIN [JsonEntitiesBasic] AS [j] ON [e].[Id] = [j].[EntityBasicId] +ORDER BY [e].[Id] +"""); + } + + public override async Task Json_with_include_on_entity_collection_and_reference(bool async) + { + await base.Json_with_include_on_entity_collection_and_reference(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], [j0].[Id], [j0].[Name], [j0].[ParentId], [j1].[Id], [j1].[Name], [j1].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j1] ON [j].[Id] = [j1].[ParentId] +ORDER BY [j].[Id], [j0].[Id] +"""); + } + + public override async Task Json_with_projection_of_json_reference_leaf_and_entity_collection(bool async) + { + await base.Json_with_projection_of_json_reference_leaf_and_entity_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_with_projection_of_json_reference_and_entity_collection(bool async) + { + await base.Json_with_projection_of_json_reference_and_entity_collection(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_with_projection_of_multiple_json_references_and_entity_collection(bool async) + { + await base.Json_with_projection_of_multiple_json_references_and_entity_collection(async); + + AssertSql( + """ +SELECT [j].[OwnedReferenceRoot], [j].[Id], JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedReferenceBranch'), [j0].[Id], [j0].[Name], [j0].[ParentId], JSON_QUERY([j].[OwnedCollectionRoot], '$[1].OwnedReferenceBranch.OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch[0].OwnedReferenceLeaf') +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_with_projection_of_json_collection_leaf_and_entity_collection(bool async) + { + await base.Json_with_projection_of_json_collection_leaf_and_entity_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_with_projection_of_json_collection_and_entity_collection(bool async) + { + await base.Json_with_projection_of_json_collection_and_entity_collection(async); + + AssertSql( + """ +SELECT [j].[OwnedCollectionRoot], [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId] +ORDER BY [j].[Id] +"""); + } + + public override async Task Json_with_projection_of_json_collection_element_and_entity_collection(bool async) + { + await base.Json_with_projection_of_json_collection_element_and_entity_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedCollectionRoot], '$[0]'), [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId], [j1].[Id], [j1].[Name], [j1].[ParentId] +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j1] ON [j].[Id] = [j1].[ParentId] +ORDER BY [j].[Id], [j0].[Id] +"""); + } + + public override async Task Json_with_projection_of_mix_of_json_collections_json_references_and_entity_collection(bool async) + { + await base.Json_with_projection_of_mix_of_json_collections_json_references_and_entity_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j1].[Id], [j1].[Name], [j1].[ParentId], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf[0]'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), [j].[OwnedCollectionRoot], JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedReferenceBranch'), JSON_QUERY([j].[OwnedCollectionRoot], '$[0].OwnedCollectionBranch') +FROM [JsonEntitiesBasic] AS [j] +LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId] +LEFT JOIN [JsonEntitiesBasicForCollection] AS [j1] ON [j].[Id] = [j1].[ParentId] +ORDER BY [j].[Id], [j0].[Id] +"""); + +// AssertSql( +//""" +//SELECT JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), [j].[Id], [j0].[Id], [j0].[Name], [j0].[ParentId], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedReferenceLeaf'), [j1].[Id], [j1].[Name], [j1].[ParentId], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), [j].[OwnedCollectionRoot] +//FROM [JsonEntitiesBasic] AS [j] +//LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId] +//LEFT JOIN [JsonEntitiesBasicForCollection] AS [j1] ON [j].[Id] = [j1].[ParentId] +//ORDER BY [j].[Id], [j0].[Id] +//"""); + } + + public override async Task Json_all_types_entity_projection(bool async) + { + await base.Json_all_types_entity_projection(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +"""); + } + + public override async Task Json_all_types_projection_from_owned_entity_reference(bool async) + { + await base.Json_all_types_projection_from_owned_entity_reference(async); + + AssertSql( + """ +SELECT [j].[Reference], [j].[Id] +FROM [JsonEntitiesAllTypes] AS [j] +"""); + } + + public override async Task Json_all_types_projection_individual_properties(bool async) + { + await base.Json_all_types_projection_individual_properties(async); + + AssertSql( + """ +SELECT JSON_VALUE([j].[Reference], '$.TestDefaultString') AS [TestDefaultString], JSON_VALUE([j].[Reference], '$.TestMaxLengthString') AS [TestMaxLengthString], CAST(JSON_VALUE([j].[Reference], '$.TestBoolean') AS bit) AS [TestBoolean], CAST(JSON_VALUE([j].[Reference], '$.TestByte') AS tinyint) AS [TestByte], JSON_VALUE([j].[Reference], '$.TestCharacter') AS [TestCharacter], CAST(JSON_VALUE([j].[Reference], '$.TestDateTime') AS datetime2) AS [TestDateTime], CAST(JSON_VALUE([j].[Reference], '$.TestDateTimeOffset') AS datetimeoffset) AS [TestDateTimeOffset], CAST(JSON_VALUE([j].[Reference], '$.TestDecimal') AS decimal(18,3)) AS [TestDecimal], CAST(JSON_VALUE([j].[Reference], '$.TestDouble') AS float) AS [TestDouble], CAST(JSON_VALUE([j].[Reference], '$.TestGuid') AS uniqueidentifier) AS [TestGuid], CAST(JSON_VALUE([j].[Reference], '$.TestInt16') AS smallint) AS [TestInt16], CAST(JSON_VALUE([j].[Reference], '$.TestInt32') AS int) AS [TestInt32], CAST(JSON_VALUE([j].[Reference], '$.TestInt64') AS bigint) AS [TestInt64], CAST(JSON_VALUE([j].[Reference], '$.TestSignedByte') AS smallint) AS [TestSignedByte], CAST(JSON_VALUE([j].[Reference], '$.TestSingle') AS real) AS [TestSingle], CAST(JSON_VALUE([j].[Reference], '$.TestTimeSpan') AS time) AS [TestTimeSpan], CAST(JSON_VALUE([j].[Reference], '$.TestDateOnly') AS date) AS [TestDateOnly], CAST(JSON_VALUE([j].[Reference], '$.TestTimeOnly') AS time) AS [TestTimeOnly], CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt16') AS int) AS [TestUnsignedInt16], CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt32') AS bigint) AS [TestUnsignedInt32], CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt64') AS decimal(20,0)) AS [TestUnsignedInt64], CAST(JSON_VALUE([j].[Reference], '$.TestEnum') AS int) AS [TestEnum], CAST(JSON_VALUE([j].[Reference], '$.TestEnumWithIntConverter') AS int) AS [TestEnumWithIntConverter], CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnum') AS int) AS [TestNullableEnum], CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnumWithIntConverter') AS int) AS [TestNullableEnumWithIntConverter], JSON_VALUE([j].[Reference], '$.TestNullableEnumWithConverterThatHandlesNulls') AS [TestNullableEnumWithConverterThatHandlesNulls] +FROM [JsonEntitiesAllTypes] AS [j] +"""); + } + + public override async Task Json_boolean_predicate(bool async) + { + await base.Json_boolean_predicate(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestBoolean') AS bit) = CAST(1 AS bit) +"""); + } + + public override async Task Json_boolean_predicate_negated(bool async) + { + await base.Json_boolean_predicate_negated(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestBoolean') AS bit) = CAST(0 AS bit) +"""); + } + + public override async Task Json_boolean_projection(bool async) + { + await base.Json_boolean_projection(async); + + AssertSql( + """ +SELECT CAST(JSON_VALUE([j].[Reference], '$.TestBoolean') AS bit) +FROM [JsonEntitiesAllTypes] AS [j] +"""); + } + + public override async Task Json_boolean_projection_negated(bool async) + { + await base.Json_boolean_projection_negated(async); + + AssertSql( + """ +SELECT ~CAST(JSON_VALUE([j].[Reference], '$.TestBoolean') AS bit) +FROM [JsonEntitiesAllTypes] AS [j] +"""); + } + + public override async Task Json_predicate_on_default_string(bool async) + { + await base.Json_predicate_on_default_string(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.TestDefaultString') <> N'MyDefaultStringInReference1' OR JSON_VALUE([j].[Reference], '$.TestDefaultString') IS NULL +"""); + } + + public override async Task Json_predicate_on_max_length_string(bool async) + { + await base.Json_predicate_on_max_length_string(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.TestMaxLengthString') <> N'Foo' OR JSON_VALUE([j].[Reference], '$.TestMaxLengthString') IS NULL +"""); + } + + public override async Task Json_predicate_on_string_condition(bool async) + { + await base.Json_predicate_on_string_condition(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CASE + WHEN CAST(JSON_VALUE([j].[Reference], '$.TestBoolean') AS bit) = CAST(0 AS bit) THEN JSON_VALUE([j].[Reference], '$.TestMaxLengthString') + ELSE JSON_VALUE([j].[Reference], '$.TestDefaultString') +END = N'MyDefaultStringInReference1' +"""); + } + + public override async Task Json_predicate_on_byte(bool async) + { + await base.Json_predicate_on_byte(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestByte') AS tinyint) <> CAST(3 AS tinyint) OR CAST(JSON_VALUE([j].[Reference], '$.TestByte') AS tinyint) IS NULL +"""); + } + + public override async Task Json_predicate_on_byte_array(bool async) + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "OpenJson support not yet supported for JSON native data type.", + (await Assert.ThrowsAsync( + () => base.Json_predicate_on_byte_array(async))).Message); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +OUTER APPLY OPENJSON([j].[Reference]) WITH ([TestByteArray] varbinary(max) '$.TestByteArray') AS [t] +WHERE [t].[TestByteArray] <> 0x010203 OR [t].[TestByteArray] IS NULL +"""); + } + + public override async Task Json_predicate_on_character(bool async) + { + await base.Json_predicate_on_character(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.TestCharacter') <> N'z' OR JSON_VALUE([j].[Reference], '$.TestCharacter') IS NULL +"""); + } + + public override async Task Json_predicate_on_datetime(bool async) + { + await base.Json_predicate_on_datetime(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestDateTime') AS datetime2) <> '2000-01-03T00:00:00.0000000' OR CAST(JSON_VALUE([j].[Reference], '$.TestDateTime') AS datetime2) IS NULL +"""); + } + + public override async Task Json_predicate_on_datetimeoffset(bool async) + { + await base.Json_predicate_on_datetimeoffset(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestDateTimeOffset') AS datetimeoffset) <> '2000-01-04T00:00:00.0000000+03:02' OR CAST(JSON_VALUE([j].[Reference], '$.TestDateTimeOffset') AS datetimeoffset) IS NULL +"""); + } + + public override async Task Json_predicate_on_decimal(bool async) + { + await base.Json_predicate_on_decimal(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestDecimal') AS decimal(18,3)) <> 1.35 OR CAST(JSON_VALUE([j].[Reference], '$.TestDecimal') AS decimal(18,3)) IS NULL +"""); + } + + public override async Task Json_predicate_on_double(bool async) + { + await base.Json_predicate_on_double(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestDouble') AS float) <> 33.25E0 OR CAST(JSON_VALUE([j].[Reference], '$.TestDouble') AS float) IS NULL +"""); + } + + public override async Task Json_predicate_on_enum(bool async) + { + await base.Json_predicate_on_enum(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestEnum') AS int) <> 2 OR CAST(JSON_VALUE([j].[Reference], '$.TestEnum') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_enumwithintconverter(bool async) + { + await base.Json_predicate_on_enumwithintconverter(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestEnumWithIntConverter') AS int) <> -3 OR CAST(JSON_VALUE([j].[Reference], '$.TestEnumWithIntConverter') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_guid(bool async) + { + await base.Json_predicate_on_guid(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestGuid') AS uniqueidentifier) <> '00000000-0000-0000-0000-000000000000' OR CAST(JSON_VALUE([j].[Reference], '$.TestGuid') AS uniqueidentifier) IS NULL +"""); + } + + public override async Task Json_predicate_on_int16(bool async) + { + await base.Json_predicate_on_int16(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestInt16') AS smallint) <> CAST(3 AS smallint) OR CAST(JSON_VALUE([j].[Reference], '$.TestInt16') AS smallint) IS NULL +"""); + } + + public override async Task Json_predicate_on_int32(bool async) + { + await base.Json_predicate_on_int32(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestInt32') AS int) <> 33 OR CAST(JSON_VALUE([j].[Reference], '$.TestInt32') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_int64(bool async) + { + await base.Json_predicate_on_int64(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestInt64') AS bigint) <> CAST(333 AS bigint) OR CAST(JSON_VALUE([j].[Reference], '$.TestInt64') AS bigint) IS NULL +"""); + } + + public override async Task Json_predicate_on_nullableenum1(bool async) + { + await base.Json_predicate_on_nullableenum1(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnum') AS int) <> -1 OR CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnum') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_nullableenum2(bool async) + { + await base.Json_predicate_on_nullableenum2(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnum') AS int) IS NOT NULL +"""); + } + + public override async Task Json_predicate_on_nullableenumwithconverter1(bool async) + { + await base.Json_predicate_on_nullableenumwithconverter1(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnumWithIntConverter') AS int) <> 2 OR CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnumWithIntConverter') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_nullableenumwithconverter2(bool async) + { + await base.Json_predicate_on_nullableenumwithconverter2(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestNullableEnumWithIntConverter') AS int) IS NOT NULL +"""); + } + + public override async Task Json_predicate_on_nullableenumwithconverterthathandlesnulls1(bool async) + { + await base.Json_predicate_on_nullableenumwithconverterthathandlesnulls1(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.TestNullableEnumWithConverterThatHandlesNulls') <> N'One' OR JSON_VALUE([j].[Reference], '$.TestNullableEnumWithConverterThatHandlesNulls') IS NULL +"""); + } + + public override async Task Json_predicate_on_nullableenumwithconverterthathandlesnulls2(bool async) + { + await base.Json_predicate_on_nullableenumwithconverterthathandlesnulls2(async); + + AssertSql( + """ +x +"""); + } + + public override async Task Json_predicate_on_nullableint321(bool async) + { + await base.Json_predicate_on_nullableint321(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestNullableInt32') AS int) <> 100 OR CAST(JSON_VALUE([j].[Reference], '$.TestNullableInt32') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_nullableint322(bool async) + { + await base.Json_predicate_on_nullableint322(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestNullableInt32') AS int) IS NOT NULL +"""); + } + + public override async Task Json_predicate_on_signedbyte(bool async) + { + await base.Json_predicate_on_signedbyte(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestSignedByte') AS smallint) <> CAST(100 AS smallint) OR CAST(JSON_VALUE([j].[Reference], '$.TestSignedByte') AS smallint) IS NULL +"""); + } + + public override async Task Json_predicate_on_single(bool async) + { + await base.Json_predicate_on_single(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestSingle') AS real) <> CAST(10.4 AS real) OR CAST(JSON_VALUE([j].[Reference], '$.TestSingle') AS real) IS NULL +"""); + } + + public override async Task Json_predicate_on_timespan(bool async) + { + await base.Json_predicate_on_timespan(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestTimeSpan') AS time) <> '03:02:00' OR CAST(JSON_VALUE([j].[Reference], '$.TestTimeSpan') AS time) IS NULL +"""); + } + + public override async Task Json_predicate_on_dateonly(bool async) + { + await base.Json_predicate_on_dateonly(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestDateOnly') AS date) <> '0003-02-01' OR CAST(JSON_VALUE([j].[Reference], '$.TestDateOnly') AS date) IS NULL +"""); + } + + public override async Task Json_predicate_on_timeonly(bool async) + { + await base.Json_predicate_on_timeonly(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestTimeOnly') AS time) <> '03:02:00' OR CAST(JSON_VALUE([j].[Reference], '$.TestTimeOnly') AS time) IS NULL +"""); + } + + public override async Task Json_predicate_on_unisgnedint16(bool async) + { + await base.Json_predicate_on_unisgnedint16(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt16') AS int) <> 100 OR CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt16') AS int) IS NULL +"""); + } + + public override async Task Json_predicate_on_unsignedint32(bool async) + { + await base.Json_predicate_on_unsignedint32(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt32') AS bigint) <> CAST(1000 AS bigint) OR CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt32') AS bigint) IS NULL +"""); + } + + public override async Task Json_predicate_on_unsignedint64(bool async) + { + await base.Json_predicate_on_unsignedint64(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt64') AS decimal(20,0)) <> 10000.0 OR CAST(JSON_VALUE([j].[Reference], '$.TestUnsignedInt64') AS decimal(20,0)) IS NULL +"""); + } + + public override async Task Json_predicate_on_bool_converted_to_int_zero_one(bool async) + { + await base.Json_predicate_on_bool_converted_to_int_zero_one(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.BoolConvertedToIntZeroOne') AS int) = 1 +"""); + } + + public override async Task Json_predicate_on_bool_converted_to_int_zero_one_with_explicit_comparison(bool async) + { + await base.Json_predicate_on_bool_converted_to_int_zero_one_with_explicit_comparison(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.BoolConvertedToIntZeroOne') AS int) = 0 +"""); + } + + public override async Task Json_predicate_on_bool_converted_to_string_True_False(bool async) + { + await base.Json_predicate_on_bool_converted_to_string_True_False(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.BoolConvertedToStringTrueFalse') = N'True' +"""); + } + + public override async Task Json_predicate_on_bool_converted_to_string_True_False_with_explicit_comparison(bool async) + { + await base.Json_predicate_on_bool_converted_to_string_True_False_with_explicit_comparison(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.BoolConvertedToStringTrueFalse') = N'True' +"""); + } + + public override async Task Json_predicate_on_bool_converted_to_string_Y_N(bool async) + { + await base.Json_predicate_on_bool_converted_to_string_Y_N(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.BoolConvertedToStringYN') = N'Y' +"""); + } + + public override async Task Json_predicate_on_bool_converted_to_string_Y_N_with_explicit_comparison(bool async) + { + await base.Json_predicate_on_bool_converted_to_string_Y_N_with_explicit_comparison(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE JSON_VALUE([j].[Reference], '$.BoolConvertedToStringYN') = N'N' +"""); + } + + public override async Task Json_predicate_on_int_zero_one_converted_to_bool(bool async) + { + await base.Json_predicate_on_int_zero_one_converted_to_bool(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.IntZeroOneConvertedToBool') AS bit) = CAST(1 AS bit) +"""); + } + + public override async Task Json_predicate_on_string_True_False_converted_to_bool(bool async) + { + await base.Json_predicate_on_string_True_False_converted_to_bool(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.StringTrueFalseConvertedToBool') AS bit) = CAST(0 AS bit) +"""); + } + + public override async Task Json_predicate_on_string_Y_N_converted_to_bool(bool async) + { + await base.Json_predicate_on_string_Y_N_converted_to_bool(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE CAST(JSON_VALUE([j].[Reference], '$.StringYNConvertedToBool') AS bit) = CAST(0 AS bit) +"""); + } + + public override async Task FromSql_on_entity_with_json_basic(bool async) + { + await base.FromSql_on_entity_with_json_basic(async); + + AssertSql( + """ +SELECT [m].[Id], [m].[EntityBasicId], [m].[Name], [m].[OwnedCollectionRoot], [m].[OwnedReferenceRoot] +FROM ( + SELECT * FROM "JsonEntitiesBasic" AS j +) AS [m] +"""); + } + + public virtual async Task FromSqlInterpolated_on_entity_with_json_with_predicate(bool async) + { + var parameter = new SqlParameter { ParameterName = "prm", Value = 1 }; + await AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSql( + Fixture.TestStore.NormalizeDelimitersInInterpolatedString( + $"SELECT * FROM [JsonEntitiesBasic] AS j WHERE [j].[Id] = {parameter}")), + ss => ss.Set()); + + AssertSql( + """ +prm='1' + +SELECT [m].[Id], [m].[EntityBasicId], [m].[Name], [m].[OwnedCollectionRoot], [m].[OwnedReferenceRoot] +FROM ( + SELECT * FROM "JsonEntitiesBasic" AS j WHERE "j"."Id" = @prm +) AS [m] +"""); + } + + public override async Task FromSql_on_entity_with_json_project_json_reference(bool async) + { + await base.FromSql_on_entity_with_json_project_json_reference(async); + + AssertSql( + """ +SELECT JSON_QUERY([m].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), [m].[Id] +FROM ( + SELECT * FROM "JsonEntitiesBasic" AS j +) AS [m] +"""); + } + + public override async Task FromSql_on_entity_with_json_project_json_collection(bool async) + { + await base.FromSql_on_entity_with_json_project_json_collection(async); + + AssertSql( + """ +SELECT JSON_QUERY([m].[OwnedReferenceRoot], '$.OwnedCollectionBranch'), [m].[Id] +FROM ( + SELECT * FROM "JsonEntitiesBasic" AS j +) AS [m] +"""); + } + + [ConditionalTheory(Skip = "TODO:SQLJSON Returns empty (invalid) JSON (See BadJson.cs)")] + public override async Task FromSql_on_entity_with_json_inheritance_on_base(bool async) + { + await base.FromSql_on_entity_with_json_inheritance_on_base(async); + + AssertSql( + """ +SELECT [m].[Id], [m].[Discriminator], [m].[Name], [m].[Fraction], [m].[CollectionOnBase], [m].[ReferenceOnBase], [m].[CollectionOnDerived], [m].[ReferenceOnDerived] +FROM ( + SELECT * FROM "JsonEntitiesInheritance" AS j +) AS [m] +"""); + } + + public override async Task FromSql_on_entity_with_json_inheritance_on_derived(bool async) + { + await base.FromSql_on_entity_with_json_inheritance_on_derived(async); + + AssertSql( + """ +SELECT [m].[Id], [m].[Discriminator], [m].[Name], [m].[Fraction], [m].[CollectionOnBase], [m].[ReferenceOnBase], [m].[CollectionOnDerived], [m].[ReferenceOnDerived] +FROM ( + SELECT * FROM "JsonEntitiesInheritance" AS j +) AS [m] +WHERE [m].[Discriminator] = N'JsonEntityInheritanceDerived' +"""); + } + + public override async Task FromSql_on_entity_with_json_inheritance_project_reference_on_base(bool async) + { + await base.FromSql_on_entity_with_json_inheritance_project_reference_on_base(async); + + AssertSql( + """ +SELECT [m].[ReferenceOnBase], [m].[Id] +FROM ( + SELECT * FROM "JsonEntitiesInheritance" AS j +) AS [m] +ORDER BY [m].[Id] +"""); + } + + public override async Task FromSql_on_entity_with_json_inheritance_project_reference_on_derived(bool async) + { + await base.FromSql_on_entity_with_json_inheritance_project_reference_on_derived(async); + + AssertSql( + """ +SELECT [m].[CollectionOnDerived], [m].[Id] +FROM ( + SELECT * FROM "JsonEntitiesInheritance" AS j +) AS [m] +WHERE [m].[Discriminator] = N'JsonEntityInheritanceDerived' +ORDER BY [m].[Id] +"""); + } + + + public override async Task Json_projection_nothing_interesting_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_nothing_interesting_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[Name] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_owner_entity_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_owner_entity_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_nested_collection_anonymous_projection_of_primitives_in_projection_NoTrackingWithIdentityResolution(bool async) + { + await base.Json_nested_collection_anonymous_projection_of_primitives_in_projection_NoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], [s].[key], [s].[c], [s].[c0], [s].[c1], [s].[c2], [s].[key0] +FROM [JsonEntitiesBasic] AS [j] +OUTER APPLY ( + SELECT [o].[key], CAST(JSON_VALUE([o0].[value], '$.Date') AS datetime2) AS [c], CAST(JSON_VALUE([o0].[value], '$.Enum') AS int) AS [c0], JSON_QUERY([o0].[value], '$.Enums') AS [c1], CAST(JSON_VALUE([o0].[value], '$.Fraction') AS decimal(18,2)) AS [c2], [o0].[key] AS [key0], CAST([o].[key] AS int) AS [c3], CAST([o0].[key] AS int) AS [c4] + FROM OPENJSON(CAST([j].[OwnedCollectionRoot] AS nvarchar(max)), '$') AS [o] + OUTER APPLY OPENJSON(CAST(JSON_QUERY([o].[value], '$.OwnedCollectionBranch') AS nvarchar(max)), '$') AS [o0] +) AS [s] +ORDER BY [j].[Id], [s].[c3], [s].[key], [s].[c4] +"""); + } + + public override async Task Json_projection_second_element_through_collection_element_constant_projected_after_owner_nested_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_second_element_through_collection_element_constant_projected_after_owner_nested_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_reference_collection_and_collection_element_nested_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_reference_collection_and_collection_element_nested_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedReferenceLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_projection_second_element_through_collection_element_parameter_correctly_projected_after_owner_nested_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_second_element_through_collection_element_parameter_correctly_projected_after_owner_nested_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +@__prm_0='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[' + CAST(@__prm_0 AS nvarchar(max)) + ']'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_only_second_element_through_collection_element_constant_projected_nested_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_only_second_element_through_collection_element_constant_projected_nested_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_projection_only_second_element_through_collection_element_parameter_projected_nested_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_only_second_element_through_collection_element_parameter_projected_nested_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +@__prm1_0='0' +@__prm2_1='1' + +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[' + CAST(@__prm1_0 AS nvarchar(max)) + '].OwnedCollectionLeaf[' + CAST(@__prm2_1 AS nvarchar(max)) + ']'), @__prm1_0, @__prm2_1 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_second_element_through_collection_element_constant_different_values_projected_before_owner_nested_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_second_element_through_collection_element_constant_different_values_projected_before_owner_nested_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[1]'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[1].OwnedCollectionLeaf') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_nested_collection_and_element_correct_order_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_nested_collection_and_element_correct_order_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[0].OwnedCollectionLeaf[1]') +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Json_projection_nested_collection_element_using_parameter_and_the_owner_in_correct_order_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_nested_collection_element_using_parameter_and_the_owner_in_correct_order_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +@__prm_0='0' + +SELECT [j].[Id], [j].[OwnedReferenceRoot], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[' + CAST(@__prm_0 AS nvarchar(max)) + '].OwnedCollectionLeaf[1]'), @__prm_0 +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_second_element_projected_before_owner_as_well_as_root_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_second_element_projected_before_owner_as_well_as_root_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedCollectionBranch[1]'), [j].[OwnedReferenceRoot], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Json_projection_second_element_projected_before_owner_nested_as_well_as_root_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Json_projection_second_element_projected_before_owner_nested_as_well_as_root_AsNoTrackingWithIdentityResolution(async); + + AssertSql( + """ +SELECT [j].[Id], JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf[1]'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch.OwnedCollectionLeaf'), JSON_QUERY([j].[OwnedReferenceRoot], '$.OwnedReferenceBranch'), [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs new file mode 100644 index 00000000000..7019fbd73eb --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs @@ -0,0 +1,2023 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Data.SqlClient; + +namespace Microsoft.EntityFrameworkCore.Query; + +[SqlServerCondition(SqlServerCondition.SupportsFunctions2022)] +public class PrimitiveCollectionsQuerySqlServerJsonTypeTest : PrimitiveCollectionsQueryRelationalTestBase< + PrimitiveCollectionsQuerySqlServerJsonTypeTest.PrimitiveCollectionsQuerySqlServerFixture> +{ + public PrimitiveCollectionsQuerySqlServerJsonTypeTest(PrimitiveCollectionsQuerySqlServerFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + public override async Task Inline_collection_of_ints_Contains(bool async) + { + await base.Inline_collection_of_ints_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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN (10, 999) +"""); + } + + public override async Task Inline_collection_of_nullable_ints_Contains(bool async) + { + await base.Inline_collection_of_nullable_ints_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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableInt] IN (10, 999) +"""); + } + + public override async Task Inline_collection_of_nullable_ints_Contains_null(bool async) + { + await base.Inline_collection_of_nullable_ints_Contains_null(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = 999 +"""); + } + + public override async Task Inline_collection_Count_with_zero_values(bool async) + { + await base.Inline_collection_Count_with_zero_values(async); + + AssertSql(); + } + + public override async Task Inline_collection_Count_with_one_value(bool async) + { + await base.Inline_collection_Count_with_one_value(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM (VALUES (CAST(2 AS int))) AS [v]([Value]) + WHERE [v].[Value] > [p].[Id]) = 1 +"""); + } + + public override async Task Inline_collection_Count_with_two_values(bool async) + { + await base.Inline_collection_Count_with_two_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM (VALUES (CAST(2 AS int)), (999)) AS [v]([Value]) + WHERE [v].[Value] > [p].[Id]) = 1 +"""); + } + + public override async Task Inline_collection_Count_with_three_values(bool async) + { + await base.Inline_collection_Count_with_three_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM (VALUES (CAST(2 AS int)), (999), (1000)) AS [v]([Value]) + WHERE [v].[Value] > [p].[Id]) = 2 +"""); + } + + public override async Task Inline_collection_Contains_with_zero_values(bool async) + { + await base.Inline_collection_Contains_with_zero_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 0 = 1 +"""); + } + + public override async Task Inline_collection_Contains_with_one_value(bool async) + { + await base.Inline_collection_Contains_with_one_value(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] = 2 +"""); + } + + public override async Task Inline_collection_Contains_with_two_values(bool async) + { + await base.Inline_collection_Contains_with_two_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] IN (2, 999) +"""); + } + + public override async Task Inline_collection_Contains_with_three_values(bool async) + { + await base.Inline_collection_Contains_with_three_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] IN (2, 999, 1000) +"""); + } + + public override async Task Inline_collection_Contains_with_EF_Constant(bool async) + { + await base.Inline_collection_Contains_with_EF_Constant(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] IN (2, 999, 1000) +"""); + } + + public override async Task Inline_collection_Contains_with_all_parameters(bool async) + { + await base.Inline_collection_Contains_with_all_parameters(async); + + AssertSql( + """ +@__i_0='2' +@__j_1='999' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] IN (@__i_0, @__j_1) +"""); + } + + public override async Task Inline_collection_Contains_with_constant_and_parameter(bool async) + { + await base.Inline_collection_Contains_with_constant_and_parameter(async); + + AssertSql( + """ +@__j_0='999' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] IN (2, @__j_0) +"""); + } + + public override async Task Inline_collection_Contains_with_mixed_value_types(bool async) + { + await base.Inline_collection_Contains_with_mixed_value_types(async); + + AssertSql( + """ +@__i_0='11' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN (999, @__i_0, [p].[Id], [p].[Id] + [p].[Int]) +"""); + } + + public override async Task Inline_collection_List_Contains_with_mixed_value_types(bool async) + { + await base.Inline_collection_List_Contains_with_mixed_value_types(async); + + AssertSql( + """ +@__i_0='11' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN (999, @__i_0, [p].[Id], [p].[Id] + [p].[Int]) +"""); + } + + public override async Task Inline_collection_Contains_as_Any_with_predicate(bool async) + { + await base.Inline_collection_Contains_as_Any_with_predicate(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] IN (2, 999) +"""); + } + + public override async Task Inline_collection_negated_Contains_as_All(bool async) + { + await base.Inline_collection_negated_Contains_as_All(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] NOT IN (2, 999) +"""); + } + + public override async Task Inline_collection_Min_with_two_values(bool async) + { + await base.Inline_collection_Min_with_two_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE LEAST(30, [p].[Int]) = 30 +"""); + } + + public override async Task Inline_collection_List_Min_with_two_values(bool async) + { + await base.Inline_collection_List_Min_with_two_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE LEAST(30, [p].[Int]) = 30 +"""); + } + + public override async Task Inline_collection_Max_with_two_values(bool async) + { + await base.Inline_collection_Max_with_two_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE GREATEST(30, [p].[Int]) = 30 +"""); + } + + public override async Task Inline_collection_List_Max_with_two_values(bool async) + { + await base.Inline_collection_List_Max_with_two_values(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE GREATEST(30, [p].[Int]) = 30 +"""); + } + + public override async Task Inline_collection_Min_with_three_values(bool async) + { + await base.Inline_collection_Min_with_three_values(async); + + AssertSql( + """ +@__i_0='25' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE LEAST(30, [p].[Int], @__i_0) = 25 +"""); + } + + public override async Task Inline_collection_List_Min_with_three_values(bool async) + { + await base.Inline_collection_List_Min_with_three_values(async); + + AssertSql( + """ +@__i_0='25' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE LEAST(30, [p].[Int], @__i_0) = 25 +"""); + } + + public override async Task Inline_collection_Max_with_three_values(bool async) + { + await base.Inline_collection_Max_with_three_values(async); + + AssertSql( + """ +@__i_0='35' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE GREATEST(30, [p].[Int], @__i_0) = 35 +"""); + } + + public override async Task Inline_collection_List_Max_with_three_values(bool async) + { + await base.Inline_collection_List_Max_with_three_values(async); + + AssertSql( + """ +@__i_0='35' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE GREATEST(30, [p].[Int], @__i_0) = 35 +"""); + } + + public override async Task Inline_collection_of_nullable_value_type_Min(bool async) + { + await base.Inline_collection_of_nullable_value_type_Min(async); + + AssertSql( + """ +@__i_0='25' (Nullable = true) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE LEAST(30, [p].[Int], @__i_0) = 25 +"""); + } + + public override async Task Inline_collection_of_nullable_value_type_Max(bool async) + { + await base.Inline_collection_of_nullable_value_type_Max(async); + + AssertSql( + """ +@__i_0='35' (Nullable = true) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE GREATEST(30, [p].[Int], @__i_0) = 35 +"""); + } + + public override async Task Inline_collection_of_nullable_value_type_with_null_Min(bool async) + { + await base.Inline_collection_of_nullable_value_type_with_null_Min(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE LEAST(30, [p].[NullableInt], NULL) = 30 +"""); + } + + public override async Task Inline_collection_of_nullable_value_type_with_null_Max(bool async) + { + await base.Inline_collection_of_nullable_value_type_with_null_Max(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE GREATEST(30, [p].[NullableInt], NULL) = 30 +"""); + } + + public override async Task Parameter_collection_Count(bool async) + { + await base.Parameter_collection_Count(async); + + AssertSql( + """ +@__ids_0='[2,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM OPENJSON(@__ids_0) WITH ([value] int '$') AS [i] + WHERE [i].[value] > [p].[Id]) = 1 +"""); + } + + public override async Task Parameter_collection_of_ints_Contains_int(bool async) + { + await base.Parameter_collection_of_ints_Contains_int(async); + + AssertSql( + """ +@__ints_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] +) +""", + // + """ +@__ints_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] NOT IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] +) +"""); + } + + public override async Task Parameter_collection_HashSet_of_ints_Contains_int(bool async) + { + await base.Parameter_collection_HashSet_of_ints_Contains_int(async); + + AssertSql( + """ +@__ints_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] +) +""", + // + """ +@__ints_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] NOT IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] +) +"""); + } + + public override async Task Parameter_collection_of_ints_Contains_nullable_int(bool async) + { + await base.Parameter_collection_of_ints_Contains_nullable_int(async); + + AssertSql( + """ +@__ints_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableInt] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] +) +""", + // + """ +@__ints_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableInt] NOT IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] +) OR [p].[NullableInt] IS NULL +"""); + } + + public override async Task Parameter_collection_of_nullable_ints_Contains_int(bool async) + { + await base.Parameter_collection_of_nullable_ints_Contains_int(async); + + AssertSql( + """ +@__nullableInts_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN ( + SELECT [n].[value] + FROM OPENJSON(@__nullableInts_0) WITH ([value] int '$') AS [n] +) +""", + // + """ +@__nullableInts_0='[10,999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] NOT IN ( + SELECT [n].[value] + FROM OPENJSON(@__nullableInts_0) WITH ([value] int '$') AS [n] +) +"""); + } + + public override async Task Parameter_collection_of_nullable_ints_Contains_nullable_int(bool async) + { + await base.Parameter_collection_of_nullable_ints_Contains_nullable_int(async); + + AssertSql( + """ +@__nullableInts_0_without_nulls='[999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableInt] IN ( + SELECT [n].[value] + FROM OPENJSON(@__nullableInts_0_without_nulls) AS [n] +) OR [p].[NullableInt] IS NULL +""", + // + """ +@__nullableInts_0_without_nulls='[999]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableInt] NOT IN ( + SELECT [n].[value] + FROM OPENJSON(@__nullableInts_0_without_nulls) AS [n] +) AND [p].[NullableInt] IS NOT NULL +"""); + } + + public override async Task Parameter_collection_of_strings_Contains_string(bool async) + { + await base.Parameter_collection_of_strings_Contains_string(async); + + AssertSql( + """ +@__strings_0='["10","999"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[String] IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s] +) +""", + // + """ +@__strings_0='["10","999"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[String] NOT IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s] +) +"""); + } + + public override async Task Parameter_collection_of_strings_Contains_nullable_string(bool async) + { + await base.Parameter_collection_of_strings_Contains_nullable_string(async); + + AssertSql( + """ +@__strings_0='["10","999"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableString] IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s] +) +""", + // + """ +@__strings_0='["10","999"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableString] NOT IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s] +) OR [p].[NullableString] IS NULL +"""); + } + + public override async Task Parameter_collection_of_nullable_strings_Contains_string(bool async) + { + await base.Parameter_collection_of_nullable_strings_Contains_string(async); + + AssertSql( + """ +@__strings_0='["10",null]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[String] IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s] +) +""", + // + """ +@__strings_0_without_nulls='["10"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[String] NOT IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0_without_nulls) AS [s] +) +"""); + } + + public override async Task Parameter_collection_of_nullable_strings_Contains_nullable_string(bool async) + { + await base.Parameter_collection_of_nullable_strings_Contains_nullable_string(async); + + AssertSql( + """ +@__strings_0_without_nulls='["999"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableString] IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0_without_nulls) AS [s] +) OR [p].[NullableString] IS NULL +""", + // + """ +@__strings_0_without_nulls='["999"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[NullableString] NOT IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_0_without_nulls) AS [s] +) AND [p].[NullableString] IS NOT NULL +"""); + } + + public override async Task Parameter_collection_of_DateTimes_Contains(bool async) + { + await base.Parameter_collection_of_DateTimes_Contains(async); + + AssertSql( + """ +@__dateTimes_0='["2020-01-10T12:30:00Z","9999-01-01T00:00:00Z"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[DateTime] IN ( + SELECT [d].[value] + FROM OPENJSON(@__dateTimes_0) WITH ([value] datetime '$') AS [d] +) +"""); + } + + public override async Task Parameter_collection_of_bools_Contains(bool async) + { + await base.Parameter_collection_of_bools_Contains(async); + + AssertSql( + """ +@__bools_0='[true]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Bool] IN ( + SELECT [b].[value] + FROM OPENJSON(@__bools_0) WITH ([value] bit '$') AS [b] +) +"""); + } + + public override async Task Parameter_collection_of_enums_Contains(bool async) + { + await base.Parameter_collection_of_enums_Contains(async); + + AssertSql( + """ +@__enums_0='[0,3]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Enum] IN ( + SELECT [e].[value] + FROM OPENJSON(@__enums_0) WITH ([value] int '$') AS [e] +) +"""); + } + + public override async Task Parameter_collection_null_Contains(bool async) + { + await base.Parameter_collection_null_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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Int] IN ( + SELECT [i].[value] + FROM OPENJSON(NULL) AS [i] +) +"""); + } + + public override async Task Column_collection_of_ints_Contains(bool async) + { + await base.Column_collection_of_ints_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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 10 IN ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] +) +"""); + } + + public override async Task Column_collection_of_nullable_ints_Contains(bool async) + { + await base.Column_collection_of_nullable_ints_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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 10 IN ( + SELECT [n].[value] + FROM OPENJSON([p].[NullableInts]) WITH ([value] int '$') AS [n] +) +"""); + } + + public override async Task Column_collection_of_nullable_ints_Contains_null(bool async) + { + await base.Column_collection_of_nullable_ints_Contains_null(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON([p].[NullableInts]) WITH ([value] int '$') AS [n] + WHERE [n].[value] IS NULL) +"""); + } + + public override async Task Column_collection_of_strings_contains_null(bool async) + { + await base.Column_collection_of_strings_contains_null(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 0 = 1 +"""); + } + + public override async Task Column_collection_of_nullable_strings_contains_null(bool async) + { + await base.Column_collection_of_nullable_strings_contains_null(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(CAST([p].[NullableStrings] AS nvarchar(max))) WITH ([value] nvarchar(max) '$') AS [n] + WHERE [n].[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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(1 AS bit) IN ( + SELECT [b].[value] + FROM OPENJSON(CAST([p].[Bools] AS nvarchar(max))) WITH ([value] bit '$') AS [b] +) +"""); + } + + [ConditionalFact] + public virtual async Task Json_representation_of_bool_array() + { + await using var context = CreateContext(); + + Assert.Equal( + "[true,false]", + await context.Database.SqlQuery($"SELECT [Bools] AS [Value] FROM [PrimitiveCollectionsEntity] WHERE [Id] = 1") + .SingleAsync()); + } + + public override async Task Column_collection_Count_method(bool async) + { + await base.Column_collection_Count_method(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i]) = 2 +"""); + } + + public override async Task Column_collection_Length(bool async) + { + await base.Column_collection_Length(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i]) = 2 +"""); + } + + public override async Task Column_collection_Count_with_predicate(bool async) + { + await base.Column_collection_Count_with_predicate(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + WHERE [i].[value] > 1) = 2 +"""); + } + + public override async Task Column_collection_Where_Count(bool async) + { + await base.Column_collection_Where_Count(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + WHERE [i].[value] > 1) = 2 +"""); + } + + public override async Task Column_collection_index_int(bool async) + { + await base.Column_collection_index_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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(JSON_VALUE([p].[Ints], '$[1]') AS int) = 10 +"""); + } + + public override async Task Column_collection_index_string(bool async) + { + await base.Column_collection_index_string(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE JSON_VALUE([p].[Strings], '$[1]') = N'10' +"""); + } + + public override async Task Column_collection_index_datetime(bool async) + { + await base.Column_collection_index_datetime(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(JSON_VALUE([p].[DateTimes], '$[1]') AS datetime2) = '2020-01-10T12:30:00.0000000Z' +"""); + } + + public override async Task Column_collection_index_beyond_end(bool async) + { + await base.Column_collection_index_beyond_end(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(JSON_VALUE([p].[Ints], '$[999]') AS int) = 10 +"""); + } + + public override async Task Nullable_reference_column_collection_index_equals_nullable_column(bool async) + { + // TODO: This test is incorrect, see #33784 + await base.Nullable_reference_column_collection_index_equals_nullable_column(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE JSON_VALUE([p].[NullableStrings], '$[2]') = [p].[NullableString] OR (JSON_VALUE([p].[NullableStrings], '$[2]') IS NULL AND [p].[NullableString] IS NULL) +"""); + } + + public override async Task Non_nullable_reference_column_collection_index_equals_nullable_column(bool async) + { + await base.Non_nullable_reference_column_collection_index_equals_nullable_column(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(CAST([p].[Strings] AS nvarchar(max))) AS [s]) AND JSON_VALUE([p].[Strings], '$[1]') = [p].[NullableString] +"""); + } + + public override async Task Inline_collection_index_Column(bool async) + { + await base.Inline_collection_index_Column(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT [v].[Value] + FROM (VALUES (0, CAST(1 AS int)), (1, 2), (2, 3)) AS [v]([_ord], [Value]) + ORDER BY [v].[_ord] + OFFSET [p].[Int] ROWS FETCH NEXT 1 ROWS ONLY) = 1 +"""); + } + + public override async Task Inline_collection_value_index_Column(bool async) + { + await base.Inline_collection_value_index_Column(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT [v].[Value] + FROM (VALUES (0, CAST(1 AS int)), (1, [p].[Int]), (2, 3)) AS [v]([_ord], [Value]) + ORDER BY [v].[_ord] + OFFSET [p].[Int] ROWS FETCH NEXT 1 ROWS ONLY) = 1 +"""); + } + + public override async Task Inline_collection_List_value_index_Column(bool async) + { + await base.Inline_collection_List_value_index_Column(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT [v].[Value] + FROM (VALUES (0, CAST(1 AS int)), (1, [p].[Int]), (2, 3)) AS [v]([_ord], [Value]) + ORDER BY [v].[_ord] + OFFSET [p].[Int] ROWS FETCH NEXT 1 ROWS ONLY) = 1 +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Parameter_collection_index_Column_equal_Column(bool async) + { + await base.Parameter_collection_index_Column_equal_Column(async); + + AssertSql( + """ +@__ints_0='[0,2,3]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(JSON_VALUE(@__ints_0, '$[' + CAST([p].[Int] AS nvarchar(max)) + ']') AS int) = [p].[Int] +"""); + } + + [SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] + public override async Task Parameter_collection_index_Column_equal_constant(bool async) + { + await base.Parameter_collection_index_Column_equal_constant(async); + + AssertSql( + """ +@__ints_0='[1,2,3]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(JSON_VALUE(@__ints_0, '$[' + CAST([p].[Int] AS nvarchar(max)) + ']') AS int) = 1 +"""); + } + + public override async Task Column_collection_ElementAt(bool async) + { + await base.Column_collection_ElementAt(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CAST(JSON_VALUE([p].[Ints], '$[1]') AS int) = 10 +"""); + } + + public override async Task Column_collection_First(bool async) + { + await base.Column_collection_First(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT TOP(1) CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int)) = 1 +"""); + } + + public override async Task Column_collection_FirstOrDefault(bool async) + { + await base.Column_collection_FirstOrDefault(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE COALESCE(( + SELECT TOP(1) CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int)), 0) = 1 +"""); + } + + public override async Task Column_collection_Single(bool async) + { + await base.Column_collection_Single(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT TOP(1) CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int)) = 1 +"""); + } + + public override async Task Column_collection_SingleOrDefault(bool async) + { + await base.Column_collection_SingleOrDefault(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE COALESCE(( + SELECT TOP(1) CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int)), 0) = 1 +"""); + } + + public override async Task Column_collection_Skip(bool async) + { + await base.Column_collection_Skip(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT 1 AS empty + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS + ) AS [i0]) = 2 +"""); + } + + public override async Task Column_collection_Take(bool async) + { + await base.Column_collection_Take(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 11 IN ( + SELECT TOP(2) CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int) +) +"""); + } + + public override async Task Column_collection_Skip_Take(bool async) + { + await base.Column_collection_Skip_Take(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 11 IN ( + SELECT CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY +) +"""); + } + + public override async Task Column_collection_Where_Skip(bool async) + { + await base.Column_collection_Where_Skip(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT 1 AS empty + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + WHERE CAST([i].[value] AS int) > 1 + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS + ) AS [i0]) = 3 +"""); + } + + public override async Task Column_collection_Where_Take(bool async) + { + await base.Column_collection_Where_Take(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT TOP(2) 1 AS empty + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + WHERE CAST([i].[value] AS int) > 1 + ORDER BY CAST([i].[key] AS int) + ) AS [i0]) = 2 +"""); + } + + public override async Task Column_collection_Where_Skip_Take(bool async) + { + await base.Column_collection_Where_Skip_Take(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT 1 AS empty + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + WHERE CAST([i].[value] AS int) > 1 + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY + ) AS [i0]) = 1 +"""); + } + + public override async Task Column_collection_Contains_over_subquery(bool async) + { + await base.Column_collection_Contains_over_subquery(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE 11 IN ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + WHERE [i].[value] > 1 +) +"""); + } + + public override async Task Column_collection_OrderByDescending_ElementAt(bool async) + { + await base.Column_collection_OrderByDescending_ElementAt(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + ORDER BY [i].[value] DESC + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) = 111 +"""); + } + + public override async Task Column_collection_Where_ElementAt(bool async) + { + await base.Column_collection_Where_ElementAt(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + WHERE CAST([i].[value] AS int) > 1 + ORDER BY CAST([i].[key] AS int) + OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) = 11 +"""); + } + + public override async Task Column_collection_Any(bool async) + { + await base.Column_collection_Any(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i]) +"""); + } + + public override async Task Column_collection_Distinct(bool async) + { + await base.Column_collection_Distinct(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT DISTINCT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + ) AS [i0]) = 3 +"""); + } + + public override async Task Column_collection_SelectMany(bool async) + { + await base.Column_collection_SelectMany(async); + + AssertSql( + """ +SELECT [i].[value] +FROM [PrimitiveCollectionsEntity] AS [p] +CROSS APPLY OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] +"""); + } + + public override async Task Column_collection_SelectMany_with_filter(bool async) + { + await base.Column_collection_SelectMany_with_filter(async); + + AssertSql( + """ +SELECT [i0].[value] +FROM [PrimitiveCollectionsEntity] AS [p] +CROSS APPLY ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + WHERE [i].[value] > 1 +) AS [i0] +"""); + } + + public override async Task Column_collection_SelectMany_with_Select_to_anonymous_type(bool async) + { + await base.Column_collection_SelectMany_with_Select_to_anonymous_type(async); + + AssertSql( + """ +SELECT [i].[value] AS [Original], [i].[value] + 1 AS [Incremented] +FROM [PrimitiveCollectionsEntity] AS [p] +CROSS APPLY OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] +"""); + } + + public override async Task Column_collection_projection_from_top_level(bool async) + { + await base.Column_collection_projection_from_top_level(async); + + AssertSql( + """ +SELECT [p].[Ints] +FROM [PrimitiveCollectionsEntity] AS [p] +ORDER BY [p].[Id] +"""); + } + + public override async Task Column_collection_Join_parameter_collection(bool async) + { + await base.Column_collection_Join_parameter_collection(async); + + AssertSql( + """ +@__ints_0='[11,111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + INNER JOIN OPENJSON(@__ints_0) WITH ([value] int '$') AS [i0] ON [i].[value] = [i0].[value]) = 2 +"""); + } + + public override async Task Inline_collection_Join_ordered_column_collection(bool async) + { + await base.Inline_collection_Join_ordered_column_collection(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM (VALUES (CAST(11 AS int)), (111)) AS [v]([Value]) + INNER JOIN OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] ON [v].[Value] = [i].[value]) = 2 +"""); + } + + public override async Task Parameter_collection_Concat_column_collection(bool async) + { + await base.Parameter_collection_Concat_column_collection(async); + + AssertSql( + """ +@__ints_0='[11,111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT 1 AS empty + FROM OPENJSON(@__ints_0) AS [i] + UNION ALL + SELECT 1 AS empty + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i0] + ) AS [u]) = 2 +"""); + } + + public override async Task Column_collection_Union_parameter_collection(bool async) + { + await base.Column_collection_Union_parameter_collection(async); + + AssertSql( + """ +@__ints_0='[11,111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + UNION + SELECT [i0].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i0] + ) AS [u]) = 2 +"""); + } + + public override async Task Column_collection_Intersect_inline_collection(bool async) + { + await base.Column_collection_Intersect_inline_collection(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + INTERSECT + SELECT [v].[Value] AS [value] + FROM (VALUES (CAST(11 AS int)), (111)) AS [v]([Value]) + ) AS [i0]) = 2 +"""); + } + + public override async Task Inline_collection_Except_column_collection(bool async) + { + await base.Inline_collection_Except_column_collection(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [v].[Value] + FROM (VALUES (CAST(11 AS int)), (111)) AS [v]([Value]) + EXCEPT + SELECT [i].[value] AS [Value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + ) AS [e] + WHERE [e].[Value] % 2 = 1) = 2 +"""); + } + + public override async Task Column_collection_Where_Union(bool async) + { + await base.Column_collection_Where_Union(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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + WHERE [i].[value] > 100 + UNION + SELECT [v].[Value] AS [value] + FROM (VALUES (CAST(50 AS int))) AS [v]([Value]) + ) AS [u]) = 2 +"""); + } + + public override async Task Column_collection_equality_parameter_collection(bool async) + { + // TODO:SQLJSON Json type is not comparable + Assert.Equal( + "The JSON data type cannot be compared or sorted, except when using the IS NULL operator.", + (await Assert.ThrowsAsync(() => base.Column_collection_equality_parameter_collection(async))).Message); + + AssertSql( + """ +@__ints_0='[1,10]' (Size = 8000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Ints] = @__ints_0 +"""); + } + + public override async Task Column_collection_Concat_parameter_collection_equality_inline_collection(bool async) + { + await base.Column_collection_Concat_parameter_collection_equality_inline_collection(async); + + AssertSql(); + } + + public override async Task Column_collection_equality_inline_collection(bool async) + { + // TODO:SQLJSON Json type is not comparable + Assert.Equal( + "The data types json and varchar are incompatible in the equal to operator.", + (await Assert.ThrowsAsync(() => base.Column_collection_equality_inline_collection(async))).Message); + + 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].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Ints] = '[1,10]' +"""); + } + + public override async Task Column_collection_equality_inline_collection_with_parameters(bool async) + { + await base.Column_collection_equality_inline_collection_with_parameters(async); + + AssertSql(); + } + + public override async Task Column_collection_Where_equality_inline_collection(bool async) + { + await base.Column_collection_Where_equality_inline_collection(async); + + AssertSql(); + } + + public override async Task Parameter_collection_in_subquery_Union_column_collection_as_compiled_query(bool async) + { + await base.Parameter_collection_in_subquery_Union_column_collection_as_compiled_query(async); + + AssertSql( + """ +@__ints='[10,111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [i1].[value] + FROM ( + SELECT CAST([i].[value] AS int) AS [value] + FROM OPENJSON(@__ints) AS [i] + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS + ) AS [i1] + UNION + SELECT [i0].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i0] + ) AS [u]) = 3 +"""); + } + + public override async Task Parameter_collection_in_subquery_Union_column_collection(bool async) + { + await base.Parameter_collection_in_subquery_Union_column_collection(async); + + AssertSql( + """ +@__Skip_0='[111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [s].[value] + FROM OPENJSON(@__Skip_0) WITH ([value] int '$') AS [s] + UNION + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + ) AS [u]) = 3 +"""); + } + + public override async Task Parameter_collection_in_subquery_Union_column_collection_nested(bool async) + { + await base.Parameter_collection_in_subquery_Union_column_collection_nested(async); + + AssertSql( + """ +@__Skip_0='[111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [s].[value] + FROM OPENJSON(@__Skip_0) WITH ([value] int '$') AS [s] + UNION + SELECT [i2].[value] + FROM ( + SELECT TOP(20) [i1].[value] + FROM ( + SELECT DISTINCT [i0].[value] + FROM ( + SELECT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] + ORDER BY [i].[value] + OFFSET 1 ROWS + ) AS [i0] + ) AS [i1] + ORDER BY [i1].[value] DESC + ) AS [i2] + ) AS [u]) = 3 +"""); + } + + public override void Parameter_collection_in_subquery_and_Convert_as_compiled_query() + { + base.Parameter_collection_in_subquery_and_Convert_as_compiled_query(); + + AssertSql(); + } + + public override async Task Parameter_collection_in_subquery_Count_as_compiled_query(bool async) + { + await base.Parameter_collection_in_subquery_Count_as_compiled_query(async); + + // TODO: the subquery projection contains extra columns which we should remove + AssertSql( + """ +@__ints='[10,111]' (Size = 4000) + +SELECT COUNT(*) +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT CAST([i].[value] AS int) AS [value0] + FROM OPENJSON(@__ints) AS [i] + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS + ) AS [i0] + WHERE [i0].[value0] > [p].[Id]) = 1 +"""); + } + + public override async Task Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(bool async) + { + await base.Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(async); + + AssertSql(); + } + + public override async Task Column_collection_in_subquery_Union_parameter_collection(bool async) + { + await base.Column_collection_in_subquery_Union_parameter_collection(async); + + AssertSql( + """ +@__ints_0='[10,111]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [i1].[value] + FROM ( + SELECT CAST([i].[value] AS int) AS [value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] + ORDER BY CAST([i].[key] AS int) + OFFSET 1 ROWS + ) AS [i1] + UNION + SELECT [i0].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i0] + ) AS [u]) = 3 +"""); + } + + public override async Task Project_collection_of_ints_simple(bool async) + { + await base.Project_collection_of_ints_simple(async); + + AssertSql( + """ +SELECT [p].[Ints] +FROM [PrimitiveCollectionsEntity] AS [p] +ORDER BY [p].[Id] +"""); + } + + public override async Task Project_collection_of_ints_ordered(bool async) + { + await base.Project_collection_of_ints_ordered(async); + + AssertSql( + """ +SELECT [p].[Id], CAST([i].[value] AS int) AS [value], [i].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] +ORDER BY [p].[Id], CAST([i].[value] AS int) DESC +"""); + } + + public override async Task Project_collection_of_datetimes_filtered(bool async) + { + await base.Project_collection_of_datetimes_filtered(async); + + AssertSql( + """ +SELECT [p].[Id], [d0].[value], [d0].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT CAST([d].[value] AS datetime2) AS [value], [d].[key], CAST([d].[key] AS int) AS [c] + FROM OPENJSON(CAST([p].[DateTimes] AS nvarchar(max))) AS [d] + WHERE DATEPART(day, CAST([d].[value] AS datetime2)) <> 1 +) AS [d0] +ORDER BY [p].[Id], [d0].[c] +"""); + } + + public override async Task Project_collection_of_nullable_ints_with_paging(bool async) + { + await base.Project_collection_of_nullable_ints_with_paging(async); + + AssertSql( + """ +SELECT [p].[Id], [n0].[value], [n0].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT TOP(20) CAST([n].[value] AS int) AS [value], [n].[key], CAST([n].[key] AS int) AS [c] + FROM OPENJSON([p].[NullableInts]) AS [n] + ORDER BY CAST([n].[key] AS int) +) AS [n0] +ORDER BY [p].[Id], [n0].[c] +"""); + } + + public override async Task Project_collection_of_nullable_ints_with_paging2(bool async) + { + await base.Project_collection_of_nullable_ints_with_paging2(async); + + AssertSql( + """ +SELECT [p].[Id], [n0].[value], [n0].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT CAST([n].[value] AS int) AS [value], [n].[key] + FROM OPENJSON([p].[NullableInts]) AS [n] + ORDER BY CAST([n].[value] AS int) + OFFSET 1 ROWS +) AS [n0] +ORDER BY [p].[Id], [n0].[value] +"""); + } + + public override async Task Project_collection_of_nullable_ints_with_paging3(bool async) + { + await base.Project_collection_of_nullable_ints_with_paging3(async); + + AssertSql( + """ +SELECT [p].[Id], [n0].[value], [n0].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT CAST([n].[value] AS int) AS [value], [n].[key], CAST([n].[key] AS int) AS [c] + FROM OPENJSON([p].[NullableInts]) AS [n] + ORDER BY CAST([n].[key] AS int) + OFFSET 2 ROWS +) AS [n0] +ORDER BY [p].[Id], [n0].[c] +"""); + } + + public override async Task Project_collection_of_ints_with_distinct(bool async) + { + await base.Project_collection_of_ints_with_distinct(async); + + AssertSql( + """ +SELECT [p].[Id], [i0].[value] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT DISTINCT [i].[value] + FROM OPENJSON(CAST([p].[Ints] AS nvarchar(max))) WITH ([value] int '$') AS [i] +) AS [i0] +ORDER BY [p].[Id] +"""); + } + + public override async Task Project_collection_of_nullable_ints_with_distinct(bool async) + { + await base.Project_collection_of_nullable_ints_with_distinct(async); + + AssertSql(""); + } + + public override async Task Project_collection_of_ints_with_ToList_and_FirstOrDefault(bool async) + { + await base.Project_collection_of_ints_with_ToList_and_FirstOrDefault(async); + + AssertSql( + """ +SELECT [p0].[Id], CAST([i].[value] AS int) AS [value], [i].[key] +FROM ( + SELECT TOP(1) [p].[Id], [p].[Ints] + FROM [PrimitiveCollectionsEntity] AS [p] + ORDER BY [p].[Id] +) AS [p0] +OUTER APPLY OPENJSON(CAST([p0].[Ints] AS nvarchar(max))) AS [i] +ORDER BY [p0].[Id], CAST([i].[key] AS int) +"""); + } + + public override async Task Project_empty_collection_of_nullables_and_collection_only_containing_nulls(bool async) + { + await base.Project_empty_collection_of_nullables_and_collection_only_containing_nulls(async); + + AssertSql( + """ +SELECT [p].[Id], [n1].[value], [n1].[key], [n2].[value], [n2].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT CAST([n].[value] AS int) AS [value], [n].[key], CAST([n].[key] AS int) AS [c] + FROM OPENJSON([p].[NullableInts]) AS [n] + WHERE 0 = 1 +) AS [n1] +OUTER APPLY ( + SELECT CAST([n0].[value] AS int) AS [value], [n0].[key], CAST([n0].[key] AS int) AS [c] + FROM OPENJSON([p].[NullableInts]) AS [n0] + WHERE [n0].[value] IS NULL +) AS [n2] +ORDER BY [p].[Id], [n1].[c], [n1].[key], [n2].[c] +"""); + } + + public override async Task Project_multiple_collections(bool async) + { + await base.Project_multiple_collections(async); + + AssertSql( + """ +SELECT [p].[Id], CAST([i].[value] AS int) AS [value], [i].[key], CAST([i0].[value] AS int) AS [value], [i0].[key], [d1].[value], [d1].[key], [d2].[value], [d2].[key] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i] +OUTER APPLY OPENJSON(CAST([p].[Ints] AS nvarchar(max))) AS [i0] +OUTER APPLY ( + SELECT CAST([d].[value] AS datetime2) AS [value], [d].[key], CAST([d].[key] AS int) AS [c] + FROM OPENJSON(CAST([p].[DateTimes] AS nvarchar(max))) AS [d] + WHERE DATEPART(day, CAST([d].[value] AS datetime2)) <> 1 +) AS [d1] +OUTER APPLY ( + SELECT CAST([d0].[value] AS datetime2) AS [value], [d0].[key], CAST([d0].[key] AS int) AS [c] + FROM OPENJSON(CAST([p].[DateTimes] AS nvarchar(max))) AS [d0] + WHERE CAST([d0].[value] AS datetime2) > '2000-01-01T00:00:00.0000000' +) AS [d2] +ORDER BY [p].[Id], CAST([i].[key] AS int), [i].[key], CAST([i0].[value] AS int) DESC, [i0].[key], [d1].[c], [d1].[key], [d2].[c] +"""); + } + + public override async Task Project_primitive_collections_element(bool async) + { + await base.Project_primitive_collections_element(async); + + AssertSql( + """ +SELECT CAST(JSON_VALUE([p].[Ints], '$[0]') AS int) AS [Indexer], CAST(JSON_VALUE([p].[DateTimes], '$[0]') AS datetime2) AS [EnumerableElementAt], JSON_VALUE([p].[Strings], '$[1]') AS [QueryableElementAt] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE [p].[Id] < 4 +ORDER BY [p].[Id] +"""); + } + + public override async Task Project_inline_collection(bool async) + { + await base.Project_inline_collection(async); + + AssertSql( + """ +SELECT [p].[String] +FROM [PrimitiveCollectionsEntity] AS [p] +"""); + } + + public override async Task Project_inline_collection_with_Union(bool async) + { + await base.Project_inline_collection_with_Union(async); + + AssertSql( + """ +SELECT [p].[Id], [u].[Value] +FROM [PrimitiveCollectionsEntity] AS [p] +OUTER APPLY ( + SELECT [v].[Value] + FROM (VALUES ([p].[String])) AS [v]([Value]) + UNION + SELECT [p0].[String] AS [Value] + FROM [PrimitiveCollectionsEntity] AS [p0] +) AS [u] +ORDER BY [p].[Id] +"""); + } + + public override async Task Project_inline_collection_with_Concat(bool async) + { + await base.Project_inline_collection_with_Concat(async); + + AssertSql(); + } + + public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async) + { + await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async); + + AssertSql( + """ +@__ints_0='[1,2,3]' (Size = 4000) +@__strings_1='["one","two","three"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CASE + WHEN [p].[Int] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] + ) THEN N'one' + ELSE N'two' +END IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_1) WITH ([value] nvarchar(max) '$') AS [s] +) +"""); + } + + public override async Task Nested_contains_with_arrays_and_no_inferred_type_mapping(bool async) + { + await base.Nested_contains_with_arrays_and_no_inferred_type_mapping(async); + + AssertSql( + """ +@__ints_0='[1,2,3]' (Size = 4000) +@__strings_1='["one","two","three"]' (Size = 4000) + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE CASE + WHEN [p].[Int] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ints_0) WITH ([value] int '$') AS [i] + ) THEN N'one' + ELSE N'two' +END IN ( + SELECT [s].[value] + FROM OPENJSON(@__strings_1) WITH ([value] nvarchar(max) '$') AS [s] +) +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private PrimitiveCollectionsContext CreateContext() + => Fixture.CreateContext(); + + public class PrimitiveCollectionsQuerySqlServerFixture : PrimitiveCollectionsQueryFixtureBase, ITestSqlLoggerFactory + { + protected override string StoreName + => "PrimitiveCollectionsJsonTypeTest"; + + public TestSqlLoggerFactory TestSqlLoggerFactory + => (TestSqlLoggerFactory)ListLoggerFactory; + + protected override ITestStoreFactory TestStoreFactory + => SqlServerTestStoreFactory.Instance; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + => base.AddOptions(builder).UseSqlServer(b => b.UseSqlServerCompatibilityLevel(160)); + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity( + b => + { + // Map DateTime to non-default datetime instead of the default datetime2 to exercise type mapping inference + b.Property(p => p.DateTime).HasColumnType("datetime"); + b.PrimitiveCollection(e => e.Strings).HasColumnType("json"); + b.PrimitiveCollection(e => e.Ints).HasColumnType("json"); + b.PrimitiveCollection(e => e.DateTimes).HasColumnType("json"); + b.PrimitiveCollection(e => e.Bools).HasColumnType("json"); + b.PrimitiveCollection(e => e.Ints).HasColumnType("json"); + b.PrimitiveCollection(e => e.Enums).HasColumnType("json"); + b.PrimitiveCollection(e => e.NullableStrings).HasColumnType("json"); + }); + } + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs new file mode 100644 index 00000000000..5f570de2d4d --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable +using Microsoft.EntityFrameworkCore.TestModels.JsonQuery; + +namespace Microsoft.EntityFrameworkCore.Update; + +public class JsonUpdateJsonTypeSqlServerFixture : JsonUpdateSqlServerFixture +{ + protected override string StoreName + => "JsonUpdateJsonTypeTest"; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.OwnedReferenceRoot).ToJson("OwnedReferenceRoot", "json"); + b.OwnsMany(x => x.OwnedCollectionRoot).ToJson("OwnedCollectionRoot", "json"); + }); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.ReferenceOnBase).ToJson("ReferenceOnBase", "json"); + b.OwnsMany(x => x.CollectionOnBase).ToJson("CollectionOnBase", "json"); + }); + + modelBuilder.Entity( + b => + { + b.HasBaseType(); + b.OwnsOne(x => x.ReferenceOnDerived).ToJson("ReferenceOnDerived", "json"); + b.OwnsMany(x => x.CollectionOnDerived).ToJson("CollectionOnDerived", "json"); + }); + + modelBuilder.Entity( + b => + { + b.OwnsOne(x => x.Reference).ToJson("Reference", "json"); + b.OwnsMany(x => x.Collection).ToJson("Collection", "json"); + b.PrimitiveCollection(e => e.TestDefaultStringCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestMaxLengthStringCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestInt16Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestInt32Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestDecimalCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestDateTimeCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestDateTimeOffsetCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestTimeSpanCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestInt64Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestDoubleCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestSingleCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestBooleanCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestCharacterCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestByteCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestGuidCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestUnsignedInt16Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestUnsignedInt32Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestUnsignedInt64Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestSignedByteCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableInt32Collection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestEnumCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestEnumWithIntConverterCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableEnumCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableEnumWithIntConverterCollection).HasColumnType("json"); + b.PrimitiveCollection(e => e.TestNullableEnumWithConverterThatHandlesNullsCollection).HasColumnType("json"); + }); + + modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson("Reference", "json"); + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs new file mode 100644 index 00000000000..90721173d9c --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs @@ -0,0 +1,2962 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable +using Xunit.Sdk; + +namespace Microsoft.EntityFrameworkCore.Update; + +public class JsonUpdateJsonTypeSqlServerTest : JsonUpdateTestBase +{ + public JsonUpdateJsonTypeSqlServerTest(JsonUpdateJsonTypeSqlServerFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Add_element_to_json_collection_branch() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Add_element_to_json_collection_branch())).InnerException?.Message); + + AssertSql( + """ +@p0='[{"Date":"2101-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":10.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_c1_c1"},{"SomethingSomething":"e1_r_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_c1_r"}},{"Date":"2102-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":10.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_c2_c1"},{"SomethingSomething":"e1_r_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_c2_r"}},{"Date":"2010-10-10T00:00:00","Enum":-3,"Enums":null,"Fraction":42.42,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":[{"SomethingSomething":"ss1"},{"SomethingSomething":"ss2"}],"OwnedReferenceLeaf":{"SomethingSomething":"ss3"}}]' (Nullable = false) (Size = 789) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedCollectionBranch', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Add_element_to_json_collection_leaf() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Add_element_to_json_collection_leaf())).InnerException?.Message); + + AssertSql( + """ +@p0='[{"SomethingSomething":"e1_r_r_c1"},{"SomethingSomething":"e1_r_r_c2"},{"SomethingSomething":"ss1"}]' (Nullable = false) (Size = 100) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedReferenceBranch.OwnedCollectionLeaf', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Add_element_to_json_collection_on_derived() + { + await base.Add_element_to_json_collection_on_derived(); + + AssertSql( + """ +@p0='[{"Date":"2221-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":221.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"d2_r_c1"},{"SomethingSomething":"d2_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"d2_r_r"}},{"Date":"2222-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":222.1,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"d2_r_c1"},{"SomethingSomething":"d2_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"d2_r_r"}},{"Date":"2010-10-10T00:00:00","Enum":-3,"Enums":null,"Fraction":42.42,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":[{"SomethingSomething":"ss1"},{"SomethingSomething":"ss2"}],"OwnedReferenceLeaf":{"SomethingSomething":"ss3"}}]' (Nullable = false) (Size = 773) +@p1='2' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesInheritance] SET [CollectionOnDerived] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Discriminator], [j].[Name], [j].[Fraction], [j].[CollectionOnBase], [j].[ReferenceOnBase], [j].[CollectionOnDerived], [j].[ReferenceOnDerived] +FROM [JsonEntitiesInheritance] AS [j] +WHERE [j].[Discriminator] = N'JsonEntityInheritanceDerived' +"""); + } + + public override async Task Add_element_to_json_collection_root() + { + await base.Add_element_to_json_collection_root(); + + AssertSql( + """ +@p0='[{"Name":"e1_c1","Names":["e1_c11","e1_c12"],"Number":11,"Numbers":[-1000,0,1000],"OwnedCollectionBranch":[{"Date":"2111-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":11.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_c1_c1"},{"SomethingSomething":"e1_c1_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c1_r"}},{"Date":"2112-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":11.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_c2_c1"},{"SomethingSomething":"e1_c1_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c2_r"}}],"OwnedReferenceBranch":{"Date":"2110-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":11.0,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_r_c1"},{"SomethingSomething":"e1_c1_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_r_r"}}},{"Name":"e1_c2","Names":["e1_c21","e1_c22"],"Number":12,"Numbers":[-1001,0,1001],"OwnedCollectionBranch":[{"Date":"2121-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":12.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_c1_c1"},{"SomethingSomething":"e1_c2_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_c1_r"}},{"Date":"2122-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":12.2,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_c2_c1"},{"SomethingSomething":"e1_c2_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_c2_r"}}],"OwnedReferenceBranch":{"Date":"2120-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":12.0,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_r_c1"},{"SomethingSomething":"e1_c2_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_r_r"}}},{"Name":"new Name","Names":null,"Number":142,"Numbers":null,"OwnedCollectionBranch":[],"OwnedReferenceBranch":{"Date":"2010-10-10T00:00:00","Enum":-3,"Enums":null,"Fraction":42.42,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":[{"SomethingSomething":"ss1"},{"SomethingSomething":"ss2"}],"OwnedReferenceLeaf":{"SomethingSomething":"ss3"}}}]' (Nullable = false) (Size = 2268) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Add_element_to_json_collection_root_null_navigations() + { + await base.Add_element_to_json_collection_root_null_navigations(); + + AssertSql( + """ +@p0='[{"Name":"e1_c1","Names":["e1_c11","e1_c12"],"Number":11,"Numbers":[-1000,0,1000],"OwnedCollectionBranch":[{"Date":"2111-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":11.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_c1_c1"},{"SomethingSomething":"e1_c1_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c1_r"}},{"Date":"2112-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":11.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_c2_c1"},{"SomethingSomething":"e1_c1_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c2_r"}}],"OwnedReferenceBranch":{"Date":"2110-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":11.0,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_r_c1"},{"SomethingSomething":"e1_c1_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_r_r"}}},{"Name":"e1_c2","Names":["e1_c21","e1_c22"],"Number":12,"Numbers":[-1001,0,1001],"OwnedCollectionBranch":[{"Date":"2121-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":12.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_c1_c1"},{"SomethingSomething":"e1_c2_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_c1_r"}},{"Date":"2122-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":12.2,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_c2_c1"},{"SomethingSomething":"e1_c2_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_c2_r"}}],"OwnedReferenceBranch":{"Date":"2120-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":12.0,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_r_c1"},{"SomethingSomething":"e1_c2_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_r_r"}}},{"Name":"new Name","Names":null,"Number":142,"Numbers":null,"OwnedCollectionBranch":null,"OwnedReferenceBranch":{"Date":"2010-10-10T00:00:00","Enum":-3,"Enums":null,"Fraction":42.42,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":null,"OwnedReferenceLeaf":null}}]' (Nullable = false) (Size = 2191) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Add_entity_with_json() + { + await base.Add_entity_with_json(); + + AssertSql( + """ +@p0='{"Name":"RootName","Names":null,"Number":42,"Numbers":null,"OwnedCollectionBranch":[],"OwnedReferenceBranch":{"Date":"2010-10-10T00:00:00","Enum":-3,"Enums":null,"Fraction":42.42,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":[{"SomethingSomething":"ss1"},{"SomethingSomething":"ss2"}],"OwnedReferenceLeaf":{"SomethingSomething":"ss3"}}}' (Nullable = false) (Size = 353) +@p1='[]' (Nullable = false) (Size = 2) +@p2='2' +@p3=NULL (DbType = Int32) +@p4='NewEntity' (Size = 4000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [JsonEntitiesBasic] ([OwnedReferenceRoot], [OwnedCollectionRoot], [Id], [EntityBasicId], [Name]) +VALUES (@p0, @p1, @p2, @p3, @p4); +""", + // + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Add_entity_with_json_null_navigations() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Add_entity_with_json_null_navigations()); + + AssertSql( + """ +@p0='{"Name":"RootName","Names":null,"Number":42,"Numbers":null,"OwnedCollectionBranch":null,"OwnedReferenceBranch":{"Date":"2010-10-10T00:00:00","Enum":-3,"Enums":null,"Fraction":42.42,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":[{"SomethingSomething":"ss1"},{"SomethingSomething":"ss2"}],"OwnedReferenceLeaf":null}}' (Nullable = false) (Size = 331) +@p1='2' +@p2=NULL (DbType = Int32) +@p3='NewEntity' (Size = 4000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [JsonEntitiesBasic] ([OwnedReferenceRoot], [Id], [EntityBasicId], [Name]) +VALUES (@p0, @p1, @p2, @p3); +""", + // + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Add_json_reference_leaf() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Add_json_reference_leaf())).InnerException?.Message); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +""", + // + """ +@p0=NULL (Nullable = false) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedCollectionBranch[0].OwnedReferenceLeaf', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Add_json_reference_root() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Add_json_reference_root()); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +""", + // + """ +@p0=NULL (Nullable = false) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Delete_entity_with_json() + { + await base.Delete_entity_with_json(); + + AssertSql( + """ +@p0='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +DELETE FROM [JsonEntitiesBasic] +OUTPUT 1 +WHERE [Id] = @p0; +""", + // + """ +SELECT COUNT(*) +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Delete_json_collection_branch() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Delete_json_collection_branch())).InnerException?.Message); + + AssertSql( + """ +@p0=NULL (Nullable = false) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedCollectionBranch', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Delete_json_collection_root() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Delete_json_collection_root()); + + AssertSql( + """ +@p0=NULL (Nullable = false) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Delete_json_reference_leaf() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Delete_json_reference_leaf())).InnerException?.Message); + + AssertSql( + """ +@p0=NULL (Nullable = false) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedReferenceBranch.OwnedReferenceLeaf', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Delete_json_reference_root() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Delete_json_reference_root()); + + AssertSql( + """ +@p0=NULL (Nullable = false) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_element_in_json_collection_branch() + { + await base.Edit_element_in_json_collection_branch(); + + AssertSql( + """ +@p0='2111-11-11T00:00:00' (Nullable = false) (Size = 4000) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[0].OwnedCollectionBranch[0].Date', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_element_in_json_collection_root1() + { + await base.Edit_element_in_json_collection_root1(); + + AssertSql( + """ +@p0='Modified' (Nullable = false) (Size = 4000) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[0].Name', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_element_in_json_collection_root2() + { + await base.Edit_element_in_json_collection_root2(); + + AssertSql( + """ +@p0='Modified' (Nullable = false) (Size = 4000) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[1].Name', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_element_in_json_multiple_levels_partial_update() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_element_in_json_multiple_levels_partial_update())).InnerException?.Message); + + AssertSql( + """ +@p0='[{"Date":"2111-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":11.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"...and another"},{"SomethingSomething":"e1_c1_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c1_r"}},{"Date":"2112-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":11.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"yet another change"},{"SomethingSomething":"and another"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c2_r"}}]' (Nullable = false) (Size = 561) +@p1='{"Name":"edit","Names":["e1_r1","e1_r2"],"Number":10,"Numbers":[-2147483648,-1,0,1,2147483647],"OwnedCollectionBranch":[{"Date":"2101-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":10.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_c1_c1"},{"SomethingSomething":"e1_r_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_c1_r"}},{"Date":"2102-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":10.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_c2_c1"},{"SomethingSomething":"e1_r_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_c2_r"}}],"OwnedReferenceBranch":{"Date":"2111-11-11T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":10.0,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_r_c1"},{"SomethingSomething":"e1_r_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_r_r"}}}' (Nullable = false) (Size = 960) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[0].OwnedCollectionBranch', JSON_QUERY(@p0)), [OwnedReferenceRoot] = @p1 +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_element_in_json_branch_collection_and_add_element_to_the_same_collection() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_element_in_json_branch_collection_and_add_element_to_the_same_collection())).InnerException?.Message); + + AssertSql( + """ +@p0='[{"Date":"2101-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":4321.3,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_c1_c1"},{"SomethingSomething":"e1_r_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_c1_r"}},{"Date":"2102-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":10.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_c2_c1"},{"SomethingSomething":"e1_r_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_c2_r"}},{"Date":"2222-11-11T00:00:00","Enum":-3,"Enums":null,"Fraction":45.32,"NullableEnum":null,"NullableEnums":null,"OwnedCollectionLeaf":null,"OwnedReferenceLeaf":{"SomethingSomething":"cc"}}]' (Nullable = false) (Size = 735) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedCollectionBranch', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Edit_two_elements_in_the_same_json_collection() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_two_elements_in_the_same_json_collection())).InnerException?.Message); + + AssertSql( + """ +@p0='[{"SomethingSomething":"edit1"},{"SomethingSomething":"edit2"}]' (Nullable = false) (Size = 63) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedCollectionBranch[0].OwnedCollectionLeaf', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Edit_two_elements_in_the_same_json_collection_at_the_root() + { + await base.Edit_two_elements_in_the_same_json_collection_at_the_root(); + + AssertSql( + """ +@p0='[{"Name":"edit1","Names":["e1_c11","e1_c12"],"Number":11,"Numbers":[-1000,0,1000],"OwnedCollectionBranch":[{"Date":"2111-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":11.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_c1_c1"},{"SomethingSomething":"e1_c1_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c1_r"}},{"Date":"2112-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":11.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_c2_c1"},{"SomethingSomething":"e1_c1_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_c2_r"}}],"OwnedReferenceBranch":{"Date":"2110-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":11.0,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c1_r_c1"},{"SomethingSomething":"e1_c1_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c1_r_r"}}},{"Name":"edit2","Names":["e1_c21","e1_c22"],"Number":12,"Numbers":[-1001,0,1001],"OwnedCollectionBranch":[{"Date":"2121-01-01T00:00:00","Enum":2,"Enums":[-1,-1,2],"Fraction":12.1,"NullableEnum":-1,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_c1_c1"},{"SomethingSomething":"e1_c2_c1_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_c1_r"}},{"Date":"2122-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":12.2,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_c2_c1"},{"SomethingSomething":"e1_c2_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_c2_r"}}],"OwnedReferenceBranch":{"Date":"2120-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":12.0,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_c2_r_c1"},{"SomethingSomething":"e1_c2_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"e1_c2_r_r"}}}]' (Nullable = false) (Size = 1913) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_collection_element_and_reference_at_once() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_collection_element_and_reference_at_once())).InnerException?.Message); + + AssertSql( + """ +@p0='{"Date":"2102-01-01T00:00:00","Enum":-3,"Enums":[-1,-1,2],"Fraction":10.2,"NullableEnum":2,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"edit1"},{"SomethingSomething":"e1_r_c2_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"edit2"}}' (Nullable = false) (Size = 262) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedCollectionBranch[1]', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Edit_single_enum_property() + { + await base.Edit_single_enum_property(); + + AssertSql( + """ +@p0='2' +@p1='2' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[1].OwnedCollectionBranch[1].Enum', @p0), [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedReferenceBranch.Enum', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_single_numeric_property() + { + await base.Edit_single_numeric_property(); + + AssertSql( + """ +@p0='1024' +@p1='999' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[1].Number', @p0), [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.Number', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +"""); + } + + public override async Task Edit_single_property_bool() + { + await base.Edit_single_property_bool(); + + AssertSql( + """ +@p0='True' +@p1='False' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestBoolean', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestBoolean', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_byte() + { + await base.Edit_single_property_byte(); + + AssertSql( + """ +@p0='14' (Size = 1) +@p1='25' (Size = 1) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestByte', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestByte', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_char() + { + await base.Edit_single_property_char(); + + AssertSql( + """ +@p0='t' (Nullable = false) (Size = 4000) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Reference] = JSON_MODIFY([Reference], 'strict $.TestCharacter', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_datetime() + { + await base.Edit_single_property_datetime(); + + AssertSql( + """ +@p0='3000-01-01T12:34:56' (Nullable = false) (Size = 4000) +@p1='3000-01-01T12:34:56' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDateTime', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDateTime', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_datetimeoffset() + { + await base.Edit_single_property_datetimeoffset(); + + AssertSql( + """ +@p0='3000-01-01T12:34:56-04:00' (Nullable = false) (Size = 4000) +@p1='3000-01-01T12:34:56-04:00' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDateTimeOffset', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDateTimeOffset', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_decimal() + { + // TODO:SQLJSON Cannot insert decimal (See DecimalParameters.cs) + await Assert.ThrowsAsync(() => base.Edit_single_property_decimal()); + + AssertSql( + """ +@p0='-13579.01' (Precision = 18) (Scale = 3) +@p1='-13579.01' (Precision = 18) (Scale = 3) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDecimal', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDecimal', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_double() + { + await base.Edit_single_property_double(); + + AssertSql( + """ +@p0='-1.23579' +@p1='-1.23579' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDouble', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDouble', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_guid() + { + await base.Edit_single_property_guid(); + + AssertSql( + """ +@p0='12345678-1234-4321-5555-987654321000' (Nullable = false) (Size = 4000) +@p1='12345678-1234-4321-5555-987654321000' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestGuid', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestGuid', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_int16() + { + await base.Edit_single_property_int16(); + + AssertSql( + """ +@p0='-3234' +@p1='-3234' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestInt16', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestInt16', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_int32() + { + await base.Edit_single_property_int32(); + + AssertSql( + """ +@p0='-3234' +@p1='-3234' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestInt32', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestInt32', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_int64() + { + await base.Edit_single_property_int64(); + + AssertSql( + """ +@p0='-3234' +@p1='-3234' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestInt64', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestInt64', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_signed_byte() + { + await base.Edit_single_property_signed_byte(); + + AssertSql( + """ +@p0='-108' +@p1='-108' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestSignedByte', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestSignedByte', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_single() + { + await base.Edit_single_property_single(); + + AssertSql( + """ +@p0='-7.234' +@p1='-7.234' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestSingle', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestSingle', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_timespan() + { + await base.Edit_single_property_timespan(); + + AssertSql( + """ +@p0='10:01:01.007' (Nullable = false) (Size = 4000) +@p1='10:01:01.007' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestTimeSpan', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestTimeSpan', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_uint16() + { + await base.Edit_single_property_uint16(); + + AssertSql( + """ +@p0='1534' +@p1='1534' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestUnsignedInt16', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestUnsignedInt16', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_uint32() + { + await base.Edit_single_property_uint32(); + + AssertSql( + """ +@p0='1237775789' +@p1='1237775789' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestUnsignedInt32', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestUnsignedInt32', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_uint64() + { + // TODO:SQLJSON Cannot insert decimal (See DecimalParameters.cs) + await Assert.ThrowsAsync(() => base.Edit_single_property_uint64()); + + AssertSql( + """ +@p0='1234555555123456789' (Precision = 20) +@p1='1234555555123456789' (Precision = 20) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestUnsignedInt64', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestUnsignedInt64', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_dateonly() + { + await base.Edit_single_property_dateonly(); + + AssertSql( + """ +@p0='2000-02-04' (Nullable = false) (Size = 4000) +@p1='1023-01-01' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDateOnly', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDateOnly', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_string() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_string())).InnerException?.Message); + + AssertSql( + """ +@p0='["1024","2048"]' (Nullable = false) (Size = 15) +@p1='["999","997"]' (Nullable = false) (Size = 13) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[1].Names', JSON_QUERY(@p0)), [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.Names', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_nullable_int32() + { + await base.Edit_single_property_nullable_int32(); + + AssertSql( + """ +@p0='122354' +@p1='64528' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableInt32', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableInt32', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_int32_set_to_null() + { + await base.Edit_single_property_nullable_int32_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (DbType = Int32) +@p1=NULL (Nullable = false) (DbType = Int32) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableInt32', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableInt32', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_enum() + { + await base.Edit_single_property_enum(); + + AssertSql( + """ +@p0='-3' +@p1='-3' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestEnum', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestEnum', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_enum_with_int_converter() + { + await base.Edit_single_property_enum_with_int_converter(); + + AssertSql( + """ +@p0='-3' +@p1='-3' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestEnumWithIntConverter', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestEnumWithIntConverter', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_enum() + { + await base.Edit_single_property_nullable_enum(); + + AssertSql( + """ +@p0='-3' +@p1='-3' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestEnum', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestEnum', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_enum_set_to_null() + { + await base.Edit_single_property_nullable_enum_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (DbType = Int32) +@p1=NULL (Nullable = false) (DbType = Int32) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnum', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnum', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_enum_with_int_converter() + { + await base.Edit_single_property_nullable_enum_with_int_converter(); + + AssertSql( + """ +@p0='-1' +@p1='-3' +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithIntConverter', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithIntConverter', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_enum_with_int_converter_set_to_null() + { + await base.Edit_single_property_nullable_enum_with_int_converter_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (DbType = Int32) +@p1=NULL (Nullable = false) (DbType = Int32) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithIntConverter', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithIntConverter', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_enum_with_converter_that_handles_nulls() + { + await base.Edit_single_property_nullable_enum_with_converter_that_handles_nulls(); + + AssertSql( + """ +@p0='Three' (Nullable = false) (Size = 4000) +@p1='One' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithConverterThatHandlesNulls', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithConverterThatHandlesNulls', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_nullable_enum_with_converter_that_handles_nulls_set_to_null() + { + await base.Edit_single_property_nullable_enum_with_converter_that_handles_nulls_set_to_null(); + + AssertSql( + """ +@p0='Null' (Nullable = false) (Size = 4000) +@p1='Null' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithConverterThatHandlesNulls', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithConverterThatHandlesNulls', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_two_properties_on_same_entity_updates_the_entire_entity() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_two_properties_on_same_entity_updates_the_entire_entity())).InnerException?.Message); + + AssertSql( + """ +@p0='{"TestBoolean":false,"TestBooleanCollection":[true,false],"TestByte":25,"TestByteArray":"","TestByteCollection":null,"TestCharacter":"h","TestCharacterCollection":["A","B","\u0022"],"TestDateOnly":"2323-04-03","TestDateOnlyCollection":["3234-01-23","4331-01-21"],"TestDateTime":"2100-11-11T12:34:56","TestDateTimeCollection":["2000-01-01T12:34:56","3000-01-01T12:34:56"],"TestDateTimeOffset":"2200-11-11T12:34:56-05:00","TestDateTimeOffsetCollection":["2000-01-01T12:34:56-08:00"],"TestDecimal":-123450.01,"TestDecimalCollection":[-1234567890.01],"TestDefaultString":"MyDefaultStringInCollection1","TestDefaultStringCollection":["S1","\u0022S2\u0022","S3"],"TestDouble":-1.2345,"TestDoubleCollection":[-1.23456789,1.23456789,0],"TestEnum":-1,"TestEnumCollection":[-1,-3,-7],"TestEnumWithIntConverter":2,"TestEnumWithIntConverterCollection":[-1,-3,-7],"TestGuid":"00000000-0000-0000-0000-000000000000","TestGuidCollection":["12345678-1234-4321-7777-987654321000"],"TestInt16":-12,"TestInt16Collection":[-32768,0,32767],"TestInt32":32,"TestInt32Collection":[-2147483648,0,2147483647],"TestInt64":64,"TestInt64Collection":[-9223372036854775808,0,9223372036854775807],"TestMaxLengthString":"Baz","TestMaxLengthStringCollection":["S1","S2","S3"],"TestNullableEnum":-1,"TestNullableEnumCollection":[-1,null,-3,-7],"TestNullableEnumWithConverterThatHandlesNulls":"Two","TestNullableEnumWithConverterThatHandlesNullsCollection":[-1,null,-7],"TestNullableEnumWithIntConverter":-3,"TestNullableEnumWithIntConverterCollection":[-1,null,-3,-7],"TestNullableInt32":90,"TestNullableInt32Collection":[null,-2147483648,0,null,2147483647,null],"TestSignedByte":-18,"TestSignedByteCollection":[-128,0,127],"TestSingle":-1.4,"TestSingleCollection":[-1.234,0,-1.234],"TestTimeOnly":"05:07:08.0000000","TestTimeOnlyCollection":["13:42:23.0000000","07:17:25.0000000"],"TestTimeSpan":"6:05:04.003","TestTimeSpanCollection":["10:09:08.007","-9:50:51.993"],"TestUnsignedInt16":12,"TestUnsignedInt16Collection":[0,0,65535],"TestUnsignedInt32":12345,"TestUnsignedInt32Collection":[0,0,4294967295],"TestUnsignedInt64":1234567867,"TestUnsignedInt64Collection":[0,0,18446744073709551615]}' (Nullable = false) (Size = 2158) +@p1='{"TestBoolean":true,"TestBooleanCollection":[true,false],"TestByte":255,"TestByteArray":"AQID","TestByteCollection":null,"TestCharacter":"a","TestCharacterCollection":["A","B","\u0022"],"TestDateOnly":"2023-10-10","TestDateOnlyCollection":["1234-01-23","4321-01-21"],"TestDateTime":"2000-01-01T12:34:56","TestDateTimeCollection":["2000-01-01T12:34:56","3000-01-01T12:34:56"],"TestDateTimeOffset":"2000-01-01T12:34:56-08:00","TestDateTimeOffsetCollection":["2000-01-01T12:34:56-08:00"],"TestDecimal":-1234567890.01,"TestDecimalCollection":[-1234567890.01],"TestDefaultString":"MyDefaultStringInReference1","TestDefaultStringCollection":["S1","\u0022S2\u0022","S3"],"TestDouble":-1.23456789,"TestDoubleCollection":[-1.23456789,1.23456789,0],"TestEnum":-1,"TestEnumCollection":[-1,-3,-7],"TestEnumWithIntConverter":2,"TestEnumWithIntConverterCollection":[-1,-3,-7],"TestGuid":"12345678-1234-4321-7777-987654321000","TestGuidCollection":["12345678-1234-4321-7777-987654321000"],"TestInt16":-1234,"TestInt16Collection":[-32768,0,32767],"TestInt32":32,"TestInt32Collection":[-2147483648,0,2147483647],"TestInt64":64,"TestInt64Collection":[-9223372036854775808,0,9223372036854775807],"TestMaxLengthString":"Foo","TestMaxLengthStringCollection":["S1","S2","S3"],"TestNullableEnum":-1,"TestNullableEnumCollection":[-1,null,-3,-7],"TestNullableEnumWithConverterThatHandlesNulls":"Three","TestNullableEnumWithConverterThatHandlesNullsCollection":[-1,null,-7],"TestNullableEnumWithIntConverter":2,"TestNullableEnumWithIntConverterCollection":[-1,null,-3,-7],"TestNullableInt32":78,"TestNullableInt32Collection":[null,-2147483648,0,null,2147483647,null],"TestSignedByte":-128,"TestSignedByteCollection":[-128,0,127],"TestSingle":-1.234,"TestSingleCollection":[-1.234,0,-1.234],"TestTimeOnly":"11:12:13.0000000","TestTimeOnlyCollection":["11:42:23.0000000","07:17:27.0000000"],"TestTimeSpan":"10:09:08.007","TestTimeSpanCollection":["10:09:08.007","-9:50:51.993"],"TestUnsignedInt16":1234,"TestUnsignedInt16Collection":[0,0,65535],"TestUnsignedInt32":1234565789,"TestUnsignedInt32Collection":[0,0,4294967295],"TestUnsignedInt64":1234567890123456789,"TestUnsignedInt64Collection":[0,0,18446744073709551615]}' (Nullable = false) (Size = 2192) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0]', JSON_QUERY(@p0)), [Reference] = @p1 +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_a_scalar_property_and_reference_navigation_on_the_same_entity() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_a_scalar_property_and_reference_navigation_on_the_same_entity())).InnerException?.Message); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +""", + // + """ +@p0='{"Date":"2100-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":123.532,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_r_c1"},{"SomethingSomething":"e1_r_r_c2"}],"OwnedReferenceLeaf":null}' (Nullable = false) (Size = 245) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedReferenceBranch', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Edit_a_scalar_property_and_collection_navigation_on_the_same_entity() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_a_scalar_property_and_collection_navigation_on_the_same_entity())).InnerException?.Message); + + AssertSql( + """ +SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +FROM [JsonEntitiesBasic] AS [j] +""", + // + """ +@p0='{"Date":"2100-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":123.532,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":null,"OwnedReferenceLeaf":{"SomethingSomething":"e1_r_r_r"}}' (Nullable = false) (Size = 207) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedReferenceBranch', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Edit_a_scalar_property_and_another_property_behind_reference_navigation_on_the_same_entity() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_a_scalar_property_and_another_property_behind_reference_navigation_on_the_same_entity())) + .InnerException?.Message); + + AssertSql( + """ +@p0='{"Date":"2100-01-01T00:00:00","Enum":-1,"Enums":[-1,-1,2],"Fraction":523.532,"NullableEnum":null,"NullableEnums":[null,-1,2],"OwnedCollectionLeaf":[{"SomethingSomething":"e1_r_r_c1"},{"SomethingSomething":"e1_r_r_c2"}],"OwnedReferenceLeaf":{"SomethingSomething":"edit"}}' (Nullable = false) (Size = 270) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.OwnedReferenceBranch', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1; +"""); + } + + public override async Task Edit_single_property_with_converter_bool_to_int_zero_one() + { + await base.Edit_single_property_with_converter_bool_to_int_zero_one(); + + AssertSql( + """ +@p0='0' +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesConverters] SET [Reference] = JSON_MODIFY([Reference], 'strict $.BoolConvertedToIntZeroOne', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_with_converter_bool_to_string_True_False() + { + await base.Edit_single_property_with_converter_bool_to_string_True_False(); + + AssertSql( + """ +@p0='True' (Nullable = false) (Size = 4000) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesConverters] SET [Reference] = JSON_MODIFY([Reference], 'strict $.BoolConvertedToStringTrueFalse', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_with_converter_bool_to_string_Y_N() + { + await base.Edit_single_property_with_converter_bool_to_string_Y_N(); + + AssertSql( + """ +@p0='N' (Nullable = false) (Size = 4000) +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesConverters] SET [Reference] = JSON_MODIFY([Reference], 'strict $.BoolConvertedToStringYN', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_with_converter_int_zero_one_to_bool() + { + await base.Edit_single_property_with_converter_int_zero_one_to_bool(); + + AssertSql( + """ +@p0='True' +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesConverters] SET [Reference] = JSON_MODIFY([Reference], 'strict $.IntZeroOneConvertedToBool', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + [ConditionalFact] + public override async Task Edit_single_property_with_converter_string_True_False_to_bool() + { + await base.Edit_single_property_with_converter_string_True_False_to_bool(); + + AssertSql( + """ +@p0='False' +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesConverters] SET [Reference] = JSON_MODIFY([Reference], 'strict $.StringTrueFalseConvertedToBool', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + [ConditionalFact] + public override async Task Edit_single_property_with_converter_string_Y_N_to_bool() + { + await base.Edit_single_property_with_converter_string_Y_N_to_bool(); + + AssertSql( + """ +@p0='True' +@p1='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesConverters] SET [Reference] = JSON_MODIFY([Reference], 'strict $.StringYNConvertedToBool', @p0) +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Reference] +FROM [JsonEntitiesConverters] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_numeric() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_numeric())).InnerException?.Message); + + AssertSql( + """ +@p0='[1024,2048]' (Nullable = false) (Size = 11) +@p1='[999,997]' (Nullable = false) (Size = 9) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesBasic] SET [OwnedCollectionRoot] = JSON_MODIFY([OwnedCollectionRoot], 'strict $[1].Numbers', JSON_QUERY(@p0)), [OwnedReferenceRoot] = JSON_MODIFY([OwnedReferenceRoot], 'strict $.Numbers', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_bool() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_bool())).InnerException?.Message); + + AssertSql( + """ +@p0='[true,true,true,false]' (Nullable = false) (Size = 22) +@p1='[true,true,false]' (Nullable = false) (Size = 17) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestBooleanCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestBooleanCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_byte() + { + await base.Edit_single_property_collection_of_byte(); + + AssertSql( + """ +@p0='Dg==' (Nullable = false) (Size = 4000) +@p1='GRo=' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestByteCollection', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestByteCollection', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + [ConditionalFact(Skip = "TODO:SQLJSON Hangs (See InsertsHang.cs")] + public override async Task Edit_single_property_collection_of_char() + { + await base.Edit_single_property_collection_of_char(); + + AssertSql( + """ +@p0='["A","B","\u0022","\u0000"]' (Nullable = false) (Size = 4000) +@p1='["E","F","C","\u00F6","r","E","\u0022","\\"]' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestCharacterCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestCharacterCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_datetime() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_datetime())).InnerException?.Message); + + AssertSql( + """ +@p0='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Nullable = false) (Size = 67) +@p1='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Nullable = false) (Size = 67) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDateTimeCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDateTimeCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_datetimeoffset() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_datetimeoffset())).InnerException?.Message); + + AssertSql( + """ +@p0='["3000-01-01T12:34:56-04:00"]' (Nullable = false) (Size = 29) +@p1='["3000-01-01T12:34:56-04:00"]' (Nullable = false) (Size = 29) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDateTimeOffsetCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDateTimeOffsetCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_decimal() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_decimal())).InnerException?.Message); + + AssertSql( + """ +@p0='[-13579.01]' (Nullable = false) (Size = 11) +@p1='[-13579.01]' (Nullable = false) (Size = 11) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDecimalCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDecimalCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_double() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_double())).InnerException?.Message); + + AssertSql( + """ +@p0='[-1.23456789,1.23456789,0,-1.23579]' (Nullable = false) (Size = 35) +@p1='[-1.23456789,1.23456789,0,-1.23579]' (Nullable = false) (Size = 35) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDoubleCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDoubleCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_guid() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_guid())).InnerException?.Message); + + AssertSql( + """ +@p0='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 40) +@p1='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 40) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestGuidCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestGuidCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_int16() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_int16())).InnerException?.Message); + + AssertSql( + """ +@p0='[-3234]' (Nullable = false) (Size = 7) +@p1='[-3234]' (Nullable = false) (Size = 7) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestInt16Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestInt16Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_int32() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_int32())).InnerException?.Message); + + AssertSql( + """ +@p0='[-3234]' (Nullable = false) (Size = 7) +@p1='[-3234]' (Nullable = false) (Size = 7) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestInt32Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestInt32Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_int64() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_int64())).InnerException?.Message); + + AssertSql( + """ +@p0='[]' (Nullable = false) (Size = 2) +@p1='[]' (Nullable = false) (Size = 2) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestInt64Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestInt64Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_signed_byte() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_signed_byte())).InnerException?.Message); + + AssertSql( + """ +@p0='[-108]' (Nullable = false) (Size = 6) +@p1='[-108]' (Nullable = false) (Size = 6) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestSignedByteCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestSignedByteCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_single() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_single())).InnerException?.Message); + + AssertSql( + """ +@p0='[-1.234,-1.234]' (Nullable = false) (Size = 15) +@p1='[0,-1.234]' (Nullable = false) (Size = 10) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestSingleCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestSingleCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_timespan() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_timespan())).InnerException?.Message); + + AssertSql( + """ +@p0='["10:09:08.007","10:01:01.007"]' (Nullable = false) (Size = 31) +@p1='["10:01:01.007","-9:50:51.993"]' (Nullable = false) (Size = 31) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestTimeSpanCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestTimeSpanCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_dateonly() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_dateonly())).InnerException?.Message); + + AssertSql( + """ +@p0='["3234-01-23","0001-01-07"]' (Nullable = false) (Size = 27) +@p1='["0001-01-07","4321-01-21"]' (Nullable = false) (Size = 27) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestDateOnlyCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestDateOnlyCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_timeonly() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_timeonly())).InnerException?.Message); + + AssertSql( + """ +@p0='["13:42:23.0000000","01:01:07.0000000"]' (Nullable = false) (Size = 39) +@p1='["01:01:07.0000000","07:17:27.0000000"]' (Nullable = false) (Size = 39) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestTimeOnlyCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestTimeOnlyCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_uint16() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_uint16())).InnerException?.Message); + + AssertSql( + """ +@p0='[1534]' (Nullable = false) (Size = 6) +@p1='[1534]' (Nullable = false) (Size = 6) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestUnsignedInt16Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestUnsignedInt16Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_uint32() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_uint32())).InnerException?.Message); + + AssertSql( + """ +@p0='[1237775789]' (Nullable = false) (Size = 12) +@p1='[1237775789]' (Nullable = false) (Size = 12) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestUnsignedInt32Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestUnsignedInt32Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_uint64() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_uint64())).InnerException?.Message); + + AssertSql( + """ +@p0='[1234555555123456789]' (Nullable = false) (Size = 21) +@p1='[1234555555123456789]' (Nullable = false) (Size = 21) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestUnsignedInt64Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestUnsignedInt64Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_int32() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_nullable_int32())).InnerException?.Message); + + AssertSql( + """ +@p0='[null,77]' (Nullable = false) (Size = 9) +@p1='[null,-2147483648,0,null,2147483647,null,77,null]' (Nullable = false) (Size = 49) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableInt32Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableInt32Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_int32_set_to_null() + { + await base.Edit_single_property_collection_of_nullable_int32_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (Size = 4000) +@p1=NULL (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableInt32Collection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableInt32Collection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_enum() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_enum())).InnerException?.Message); + + AssertSql( + """ +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-3]' (Nullable = false) (Size = 4) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestEnumCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestEnumCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_enum_with_int_converter() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_enum_with_int_converter())).InnerException?.Message); + + AssertSql( + """ +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-3]' (Nullable = false) (Size = 4) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestEnumWithIntConverterCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestEnumWithIntConverterCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_enum() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_nullable_enum())).InnerException?.Message); + + AssertSql( + """ +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-3]' (Nullable = false) (Size = 4) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestEnumCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestEnumCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_enum_set_to_null() + { + await base.Edit_single_property_collection_of_nullable_enum_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (Size = 4000) +@p1=NULL (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_enum_with_int_converter() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_nullable_enum_with_int_converter())).InnerException?.Message); + + AssertSql( + """ +@p0='[-1,null,-7,2]' (Nullable = false) (Size = 14) +@p1='[-1,-3,-7,2]' (Nullable = false) (Size = 12) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithIntConverterCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithIntConverterCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_enum_with_int_converter_set_to_null() + { + await base.Edit_single_property_collection_of_nullable_enum_with_int_converter_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (Size = 4000) +@p1=NULL (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithIntConverterCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithIntConverterCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_enum_with_converter_that_handles_nulls() + { + // TODO:SQLJSON (See JsonTypeToFunction.cs) + Assert.Equal( + "Argument data type json is invalid for argument 3 of json_modify function.", + (await Assert.ThrowsAsync( + () => base.Edit_single_property_collection_of_nullable_enum_with_converter_that_handles_nulls())).InnerException?.Message); + + AssertSql( + """ +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-1]' (Nullable = false) (Size = 4) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithConverterThatHandlesNullsCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithConverterThatHandlesNullsCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +"""); + } + + public override async Task Edit_single_property_collection_of_nullable_enum_with_converter_that_handles_nulls_set_to_null() + { + await base.Edit_single_property_collection_of_nullable_enum_with_converter_that_handles_nulls_set_to_null(); + + AssertSql( + """ +@p0=NULL (Nullable = false) (Size = 4000) +@p1=NULL (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestNullableEnumWithConverterThatHandlesNullsCollection', JSON_QUERY(@p0)), [Reference] = JSON_MODIFY([Reference], 'strict $.TestNullableEnumWithConverterThatHandlesNullsCollection', JSON_QUERY(@p1)) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override Task Add_and_update_nested_optional_owned_collection_to_JSON(bool? value) + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + => Assert.ThrowsAsync( + () => base.Add_and_update_nested_optional_owned_collection_to_JSON(value)); + + public override Task Add_and_update_top_level_optional_owned_collection_to_JSON(bool? value) + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + => Assert.ThrowsAsync( + () => base.Add_and_update_top_level_optional_owned_collection_to_JSON(value)); + + [ConditionalTheory(Skip = "TODO:SQLJSON Hangs (See InsertsHang.cs")] + public override async Task Add_and_update_nested_optional_primitive_collection(bool? value) + { + await base.Add_and_update_nested_optional_primitive_collection(value); + + var characterCollection = value switch + { + true => "[\"A\"]", + false => "[]", + _ => "null" + }; + + var parameterSize = value switch + { + true => "1558", + false => "1555", + _ => "1557" + }; + + var updateParameter = value switch + { + true => "NULL", + false => "'[\"Z\"]'", + _ => "'[]'" + }; + + AssertSql( + @"@p0='[{""TestBoolean"":false,""TestBooleanCollection"":[],""TestByte"":0,""TestByteArray"":null,""TestByteCollection"":null,""TestCharacter"":""\u0000"",""TestCharacterCollection"":" + + characterCollection + + @",""TestDateOnly"":""0001-01-01"",""TestDateOnlyCollection"":[],""TestDateTime"":""0001-01-01T00:00:00"",""TestDateTimeCollection"":[],""TestDateTimeOffset"":""0001-01-01T00:00:00+00:00"",""TestDateTimeOffsetCollection"":[],""TestDecimal"":0,""TestDecimalCollection"":[],""TestDefaultString"":null,""TestDefaultStringCollection"":[],""TestDouble"":0,""TestDoubleCollection"":[],""TestEnum"":0,""TestEnumCollection"":[],""TestEnumWithIntConverter"":0,""TestEnumWithIntConverterCollection"":[],""TestGuid"":""00000000-0000-0000-0000-000000000000"",""TestGuidCollection"":[],""TestInt16"":0,""TestInt16Collection"":[],""TestInt32"":0,""TestInt32Collection"":[],""TestInt64"":0,""TestInt64Collection"":[],""TestMaxLengthString"":null,""TestMaxLengthStringCollection"":[],""TestNullableEnum"":null,""TestNullableEnumCollection"":[],""TestNullableEnumWithConverterThatHandlesNulls"":null,""TestNullableEnumWithConverterThatHandlesNullsCollection"":[],""TestNullableEnumWithIntConverter"":null,""TestNullableEnumWithIntConverterCollection"":[],""TestNullableInt32"":null,""TestNullableInt32Collection"":[],""TestSignedByte"":0,""TestSignedByteCollection"":[],""TestSingle"":0,""TestSingleCollection"":[],""TestTimeOnly"":""00:00:00.0000000"",""TestTimeOnlyCollection"":[],""TestTimeSpan"":""0:00:00"",""TestTimeSpanCollection"":[],""TestUnsignedInt16"":0,""TestUnsignedInt16Collection"":[],""TestUnsignedInt32"":0,""TestUnsignedInt32Collection"":[],""TestUnsignedInt64"":0,""TestUnsignedInt64Collection"":[]}]' (Nullable = false) (Size = " + + parameterSize + + @") +@p1='7624' +@p2='[]' (Size = 4000) +@p3=NULL (Size = 8000) (DbType = Binary) +@p4='[]' (Size = 4000) +@p5='[]' (Size = 4000) +@p6='[]' (Size = 4000) +@p7='[]' (Size = 4000) +@p8='[]' (Size = 4000) +@p9='[]' (Size = 4000) +@p10='[]' (Size = 4000) +@p11='[]' (Size = 4000) +@p12='[]' (Nullable = false) (Size = 4000) +@p13='[]' (Size = 4000) +@p14='[]' (Size = 4000) +@p15='[]' (Size = 4000) +@p16='[]' (Size = 4000) +@p17='[]' (Size = 4000) +@p18=NULL (Size = 4000) +@p19='[]' (Size = 4000) +@p20='[]' (Size = 4000) +@p21='[]' (Size = 4000) +@p22='[]' (Size = 4000) +@p23='[]' (Size = 4000) +@p24='[]' (Size = 4000) +@p25='[]' (Size = 4000) +@p26='[]' (Size = 4000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [JsonEntitiesAllTypes] ([Collection], [Id], [TestBooleanCollection], [TestByteCollection], [TestCharacterCollection], [TestDateTimeCollection], [TestDateTimeOffsetCollection], [TestDecimalCollection], [TestDefaultStringCollection], [TestDoubleCollection], [TestEnumCollection], [TestEnumWithIntConverterCollection], [TestGuidCollection], [TestInt16Collection], [TestInt32Collection], [TestInt64Collection], [TestMaxLengthStringCollection], [TestNullableEnumCollection], [TestNullableEnumWithConverterThatHandlesNullsCollection], [TestNullableEnumWithIntConverterCollection], [TestNullableInt32Collection], [TestSignedByteCollection], [TestSingleCollection], [TestTimeSpanCollection], [TestUnsignedInt16Collection], [TestUnsignedInt32Collection], [TestUnsignedInt64Collection]) +VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26);", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 7624 +""", + // + "@p0=" + + updateParameter + + @" (Nullable = false) (Size = 4000) +@p1='7624' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestCharacterCollection', JSON_QUERY(@p0)) +OUTPUT 1 +WHERE [Id] = @p1;", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 7624 +"""); + } + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_bool() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_bool); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_char() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_char); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_double() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_double); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_int16() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_int16); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_int32() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_int32); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_nullable_enum_set_to_null() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_nullable_enum_set_to_null); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_nullable_enum_with_int_converter() + => Assert.ThrowsAsync( + base.Edit_single_property_collection_of_collection_of_nullable_enum_with_int_converter); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_nullable_int32() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_nullable_int32); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_nullable_int32_set_to_null() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_nullable_int32_set_to_null); + + // Nested collections are not mapped in the relational model, so there is no data stored in the document for them + public override Task Edit_single_property_collection_of_collection_of_single() + => Assert.ThrowsAsync(base.Edit_single_property_collection_of_collection_of_single); + + public override async Task Edit_single_property_timeonly() + { + await base.Edit_single_property_timeonly(); + + AssertSql( + """ +@p0='01:01:07.0000000' (Nullable = false) (Size = 4000) +@p1='01:01:07.0000000' (Nullable = false) (Size = 4000) +@p2='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [Collection] = JSON_MODIFY([Collection], 'strict $[0].TestTimeOnly', @p0), [Reference] = JSON_MODIFY([Reference], 'strict $.TestTimeOnly', @p1) +OUTPUT 1 +WHERE [Id] = @p2; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_bool() + { + await base.Edit_single_property_relational_collection_of_bool(); + + AssertSql( + """ +@p1='1' +@p0='[true,true,false]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestBooleanCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_byte() + { + await base.Edit_single_property_relational_collection_of_byte(); + + AssertSql( + """ +@p1='1' +@p0='[25,26]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestByteCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + [ConditionalFact(Skip = "TODO:SQLJSON Investigate")] + public override async Task Edit_single_property_relational_collection_of_char() + { + await base.Edit_single_property_relational_collection_of_char(); + + AssertSql(); + } + + public override async Task Edit_single_property_relational_collection_of_datetime() + { + await base.Edit_single_property_relational_collection_of_datetime(); + + AssertSql( + """ +@p1='1' +@p0='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestDateTimeCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_datetimeoffset() + { + await base.Edit_single_property_relational_collection_of_datetimeoffset(); + + AssertSql( + """ +@p1='1' +@p0='["3000-01-01T12:34:56-04:00"]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestDateTimeOffsetCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_decimal() + { + await base.Edit_single_property_relational_collection_of_decimal(); + + AssertSql( + """ +@p1='1' +@p0='[-13579.01]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestDecimalCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_double() + { + await base.Edit_single_property_relational_collection_of_double(); + + AssertSql( + """ +@p1='1' +@p0='[-1.23456789,1.23456789,0,-1.23579]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestDoubleCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_guid() + { + await base.Edit_single_property_relational_collection_of_guid(); + + AssertSql( + """ +@p1='1' +@p0='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestGuidCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_int16() + { + await base.Edit_single_property_relational_collection_of_int16(); + + AssertSql( + """ +@p1='1' +@p0='[-3234]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestInt16Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_int32() + { + await base.Edit_single_property_relational_collection_of_int32(); + + AssertSql( + """ +@p1='1' +@p0='[-3234]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestInt32Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_int64() + { + await base.Edit_single_property_relational_collection_of_int64(); + + AssertSql( + """ +@p1='1' +@p0='[]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestInt64Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_signed_byte() + { + await base.Edit_single_property_relational_collection_of_signed_byte(); + + AssertSql( + """ +@p1='1' +@p0='[-108]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestSignedByteCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_single() + { + await base.Edit_single_property_relational_collection_of_single(); + + AssertSql( + """ +@p1='1' +@p0='[0,-1.234]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestSingleCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_timespan() + { + await base.Edit_single_property_relational_collection_of_timespan(); + + AssertSql( + """ +@p1='1' +@p0='["10:01:01.007","7:09:08.007"]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestTimeSpanCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_uint16() + { + await base.Edit_single_property_relational_collection_of_uint16(); + + AssertSql( + """ +@p1='1' +@p0='[1534]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestUnsignedInt16Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_uint32() + { + await base.Edit_single_property_relational_collection_of_uint32(); + + AssertSql( + """ +@p1='1' +@p0='[1237775789]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestUnsignedInt32Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_uint64() + { + await base.Edit_single_property_relational_collection_of_uint64(); + + AssertSql( + """ +@p1='1' +@p0='[1234555555123456789]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestUnsignedInt64Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_int32() + { + await base.Edit_single_property_relational_collection_of_nullable_int32(); + + AssertSql( + """ +@p1='1' +@p0='[null,-2147483648,0,null,2147483647,null,77,null]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableInt32Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_int32_set_to_null() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Edit_single_property_relational_collection_of_nullable_int32_set_to_null()); + + AssertSql( + """ +@p1='1' +@p0=NULL (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableInt32Collection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_enum() + { + await base.Edit_single_property_relational_collection_of_enum(); + + AssertSql( + """ +@p1='1' +@p0='[-3]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestEnumCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_enum_with_int_converter() + { + await base.Edit_single_property_relational_collection_of_enum_with_int_converter(); + + AssertSql( + """ +@p1='1' +@p0='[-3]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestEnumWithIntConverterCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_enum() + { + await base.Edit_single_property_relational_collection_of_nullable_enum(); + + AssertSql( + """ +@p1='1' +@p0='[-3]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestEnumCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_enum_set_to_null() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Edit_single_property_relational_collection_of_nullable_enum_set_to_null()); + + AssertSql( + """ +@p1='1' +@p0=NULL (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableEnumCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_enum_with_int_converter() + { + await base.Edit_single_property_relational_collection_of_nullable_enum_with_int_converter(); + + AssertSql( + """ +@p1='1' +@p0='[-1,-3,-7,2]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableEnumWithIntConverterCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_enum_with_int_converter_set_to_null() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Edit_single_property_relational_collection_of_nullable_enum_with_int_converter_set_to_null()); + + AssertSql( + """ +@p1='1' +@p0=NULL (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableEnumWithIntConverterCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_enum_with_converter_that_handles_nulls() + { + await base.Edit_single_property_relational_collection_of_nullable_enum_with_converter_that_handles_nulls(); + + AssertSql( + """ +@p1='1' +@p0='[-1]' (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableEnumWithConverterThatHandlesNullsCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_relational_collection_of_nullable_enum_with_converter_that_handles_nulls_set_to_null() + { + // TODO:SQLJSON Updates to null fail (See UpdateToNull.cs) + await Assert.ThrowsAsync( + () => base.Edit_single_property_relational_collection_of_nullable_enum_with_converter_that_handles_nulls_set_to_null()); + + AssertSql( + """ +@p1='1' +@p0=NULL (Size = 8000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesAllTypes] SET [TestNullableEnumWithConverterThatHandlesNullsCollection] = @p0 +OUTPUT 1 +WHERE [Id] = @p1; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + public override async Task Edit_single_property_collection_of_collection_of_int64() + { + await base.Edit_single_property_collection_of_collection_of_int64(); + + AssertSql( + """ +SELECT TOP(2) [j].[Id], [j].[TestBooleanCollection], [j].[TestByteCollection], [j].[TestCharacterCollection], [j].[TestDateTimeCollection], [j].[TestDateTimeOffsetCollection], [j].[TestDecimalCollection], [j].[TestDefaultStringCollection], [j].[TestDoubleCollection], [j].[TestEnumCollection], [j].[TestEnumWithIntConverterCollection], [j].[TestGuidCollection], [j].[TestInt16Collection], [j].[TestInt32Collection], [j].[TestInt64Collection], [j].[TestMaxLengthStringCollection], [j].[TestNullableEnumCollection], [j].[TestNullableEnumWithConverterThatHandlesNullsCollection], [j].[TestNullableEnumWithIntConverterCollection], [j].[TestNullableInt32Collection], [j].[TestSignedByteCollection], [j].[TestSingleCollection], [j].[TestTimeSpanCollection], [j].[TestUnsignedInt16Collection], [j].[TestUnsignedInt32Collection], [j].[TestUnsignedInt64Collection], [j].[Collection], [j].[Reference] +FROM [JsonEntitiesAllTypes] AS [j] +WHERE [j].[Id] = 1 +"""); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateSqlServerTest.cs index 05ce6fb7ce2..ca8b6aa0500 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateSqlServerTest.cs @@ -332,7 +332,7 @@ public override async Task Edit_element_in_json_collection_branch() AssertSql( """ -@p0='2111-11-11T00:00:00' (Nullable = false) (Size = 19) +@p0='2111-11-11T00:00:00' (Nullable = false) (Size = 4000) @p1='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -603,7 +603,7 @@ public override async Task Edit_single_property_char() AssertSql( """ -@p0='t' (Nullable = false) (Size = 1) +@p0='t' (Nullable = false) (Size = 4000) @p1='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -626,8 +626,8 @@ public override async Task Edit_single_property_datetime() AssertSql( """ -@p0='3000-01-01T12:34:56' (Nullable = false) (Size = 19) -@p1='3000-01-01T12:34:56' (Nullable = false) (Size = 19) +@p0='3000-01-01T12:34:56' (Nullable = false) (Size = 4000) +@p1='3000-01-01T12:34:56' (Nullable = false) (Size = 4000) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -650,8 +650,8 @@ public override async Task Edit_single_property_datetimeoffset() AssertSql( """ -@p0='3000-01-01T12:34:56-04:00' (Nullable = false) (Size = 25) -@p1='3000-01-01T12:34:56-04:00' (Nullable = false) (Size = 25) +@p0='3000-01-01T12:34:56-04:00' (Nullable = false) (Size = 4000) +@p1='3000-01-01T12:34:56-04:00' (Nullable = false) (Size = 4000) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -722,8 +722,8 @@ public override async Task Edit_single_property_guid() AssertSql( """ -@p0='12345678-1234-4321-5555-987654321000' (Nullable = false) (Size = 36) -@p1='12345678-1234-4321-5555-987654321000' (Nullable = false) (Size = 36) +@p0='12345678-1234-4321-5555-987654321000' (Nullable = false) (Size = 4000) +@p1='12345678-1234-4321-5555-987654321000' (Nullable = false) (Size = 4000) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -866,8 +866,8 @@ public override async Task Edit_single_property_timespan() AssertSql( """ -@p0='10:01:01.007' (Nullable = false) (Size = 12) -@p1='10:01:01.007' (Nullable = false) (Size = 12) +@p0='10:01:01.007' (Nullable = false) (Size = 4000) +@p1='10:01:01.007' (Nullable = false) (Size = 4000) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1315,7 +1315,7 @@ public override async Task Edit_single_property_with_converter_bool_to_string_Tr AssertSql( """ -@p0='True' (Nullable = false) (Size = 5) +@p0='True' (Nullable = false) (Size = 4000) @p1='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1338,7 +1338,7 @@ public override async Task Edit_single_property_with_converter_bool_to_string_Y_ AssertSql( """ -@p0='N' (Nullable = false) (Size = 1) +@p0='N' (Nullable = false) (Size = 4000) @p1='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1432,8 +1432,8 @@ public override async Task Edit_single_property_collection_of_numeric() AssertSql( """ -@p0='[1024,2048]' (Nullable = false) (Size = 4000) -@p1='[999,997]' (Nullable = false) (Size = 4000) +@p0='[1024,2048]' (Nullable = false) (Size = 11) +@p1='[999,997]' (Nullable = false) (Size = 9) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1455,8 +1455,8 @@ public override async Task Edit_single_property_collection_of_bool() AssertSql( """ -@p0='[true,true,true,false]' (Nullable = false) (Size = 4000) -@p1='[true,true,false]' (Nullable = false) (Size = 4000) +@p0='[true,true,true,false]' (Nullable = false) (Size = 22) +@p1='[true,true,false]' (Nullable = false) (Size = 17) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1479,8 +1479,8 @@ public override async Task Edit_single_property_collection_of_byte() AssertSql( """ -@p0='Dg==' (Nullable = false) (Size = 4) -@p1='GRo=' (Nullable = false) (Size = 4) +@p0='Dg==' (Nullable = false) (Size = 4000) +@p1='GRo=' (Nullable = false) (Size = 4000) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1503,8 +1503,8 @@ public override async Task Edit_single_property_collection_of_char() AssertSql( """ -@p0='["A","B","\u0022","\u0000"]' (Nullable = false) (Size = 4000) -@p1='["E","F","C","\u00F6","r","E","\u0022","\\"]' (Nullable = false) (Size = 4000) +@p0='["A","B","\u0022","\u0000"]' (Nullable = false) (Size = 27) +@p1='["E","F","C","\u00F6","r","E","\u0022","\\"]' (Nullable = false) (Size = 44) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1527,8 +1527,8 @@ public override async Task Edit_single_property_collection_of_datetime() AssertSql( """ -@p0='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Nullable = false) (Size = 4000) -@p1='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Nullable = false) (Size = 4000) +@p0='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Nullable = false) (Size = 67) +@p1='["2000-01-01T12:34:56","3000-01-01T12:34:56","3000-01-01T12:34:56"]' (Nullable = false) (Size = 67) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1551,8 +1551,8 @@ public override async Task Edit_single_property_collection_of_datetimeoffset() AssertSql( """ -@p0='["3000-01-01T12:34:56-04:00"]' (Nullable = false) (Size = 4000) -@p1='["3000-01-01T12:34:56-04:00"]' (Nullable = false) (Size = 4000) +@p0='["3000-01-01T12:34:56-04:00"]' (Nullable = false) (Size = 29) +@p1='["3000-01-01T12:34:56-04:00"]' (Nullable = false) (Size = 29) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1575,8 +1575,8 @@ public override async Task Edit_single_property_collection_of_decimal() AssertSql( """ -@p0='[-13579.01]' (Nullable = false) (Size = 4000) -@p1='[-13579.01]' (Nullable = false) (Size = 4000) +@p0='[-13579.01]' (Nullable = false) (Size = 11) +@p1='[-13579.01]' (Nullable = false) (Size = 11) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1599,8 +1599,8 @@ public override async Task Edit_single_property_collection_of_double() AssertSql( """ -@p0='[-1.23456789,1.23456789,0,-1.23579]' (Nullable = false) (Size = 4000) -@p1='[-1.23456789,1.23456789,0,-1.23579]' (Nullable = false) (Size = 4000) +@p0='[-1.23456789,1.23456789,0,-1.23579]' (Nullable = false) (Size = 35) +@p1='[-1.23456789,1.23456789,0,-1.23579]' (Nullable = false) (Size = 35) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1623,8 +1623,8 @@ public override async Task Edit_single_property_collection_of_guid() AssertSql( """ -@p0='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 4000) -@p1='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 4000) +@p0='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 40) +@p1='["12345678-1234-4321-5555-987654321000"]' (Nullable = false) (Size = 40) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1647,8 +1647,8 @@ public override async Task Edit_single_property_collection_of_int16() AssertSql( """ -@p0='[-3234]' (Nullable = false) (Size = 4000) -@p1='[-3234]' (Nullable = false) (Size = 4000) +@p0='[-3234]' (Nullable = false) (Size = 7) +@p1='[-3234]' (Nullable = false) (Size = 7) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1671,8 +1671,8 @@ public override async Task Edit_single_property_collection_of_int32() AssertSql( """ -@p0='[-3234]' (Nullable = false) (Size = 4000) -@p1='[-3234]' (Nullable = false) (Size = 4000) +@p0='[-3234]' (Nullable = false) (Size = 7) +@p1='[-3234]' (Nullable = false) (Size = 7) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1695,8 +1695,8 @@ public override async Task Edit_single_property_collection_of_int64() AssertSql( """ -@p0='[]' (Nullable = false) (Size = 4000) -@p1='[]' (Nullable = false) (Size = 4000) +@p0='[]' (Nullable = false) (Size = 2) +@p1='[]' (Nullable = false) (Size = 2) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1719,8 +1719,8 @@ public override async Task Edit_single_property_collection_of_signed_byte() AssertSql( """ -@p0='[-108]' (Nullable = false) (Size = 4000) -@p1='[-108]' (Nullable = false) (Size = 4000) +@p0='[-108]' (Nullable = false) (Size = 6) +@p1='[-108]' (Nullable = false) (Size = 6) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1743,8 +1743,8 @@ public override async Task Edit_single_property_collection_of_single() AssertSql( """ -@p0='[-1.234,-1.234]' (Nullable = false) (Size = 4000) -@p1='[0,-1.234]' (Nullable = false) (Size = 4000) +@p0='[-1.234,-1.234]' (Nullable = false) (Size = 15) +@p1='[0,-1.234]' (Nullable = false) (Size = 10) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1767,8 +1767,8 @@ public override async Task Edit_single_property_collection_of_timespan() AssertSql( """ -@p0='["10:09:08.007","10:01:01.007"]' (Nullable = false) (Size = 4000) -@p1='["10:01:01.007","-9:50:51.993"]' (Nullable = false) (Size = 4000) +@p0='["10:09:08.007","10:01:01.007"]' (Nullable = false) (Size = 31) +@p1='["10:01:01.007","-9:50:51.993"]' (Nullable = false) (Size = 31) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1791,8 +1791,8 @@ public override async Task Edit_single_property_collection_of_dateonly() AssertSql( """ -@p0='["3234-01-23","0001-01-07"]' (Nullable = false) (Size = 4000) -@p1='["0001-01-07","4321-01-21"]' (Nullable = false) (Size = 4000) +@p0='["3234-01-23","0001-01-07"]' (Nullable = false) (Size = 27) +@p1='["0001-01-07","4321-01-21"]' (Nullable = false) (Size = 27) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1815,8 +1815,8 @@ public override async Task Edit_single_property_collection_of_timeonly() AssertSql( """ -@p0='["13:42:23.0000000","01:01:07.0000000"]' (Nullable = false) (Size = 4000) -@p1='["01:01:07.0000000","07:17:27.0000000"]' (Nullable = false) (Size = 4000) +@p0='["13:42:23.0000000","01:01:07.0000000"]' (Nullable = false) (Size = 39) +@p1='["01:01:07.0000000","07:17:27.0000000"]' (Nullable = false) (Size = 39) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1839,8 +1839,8 @@ public override async Task Edit_single_property_collection_of_uint16() AssertSql( """ -@p0='[1534]' (Nullable = false) (Size = 4000) -@p1='[1534]' (Nullable = false) (Size = 4000) +@p0='[1534]' (Nullable = false) (Size = 6) +@p1='[1534]' (Nullable = false) (Size = 6) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1863,8 +1863,8 @@ public override async Task Edit_single_property_collection_of_uint32() AssertSql( """ -@p0='[1237775789]' (Nullable = false) (Size = 4000) -@p1='[1237775789]' (Nullable = false) (Size = 4000) +@p0='[1237775789]' (Nullable = false) (Size = 12) +@p1='[1237775789]' (Nullable = false) (Size = 12) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1887,8 +1887,8 @@ public override async Task Edit_single_property_collection_of_uint64() AssertSql( """ -@p0='[1234555555123456789]' (Nullable = false) (Size = 4000) -@p1='[1234555555123456789]' (Nullable = false) (Size = 4000) +@p0='[1234555555123456789]' (Nullable = false) (Size = 21) +@p1='[1234555555123456789]' (Nullable = false) (Size = 21) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1911,8 +1911,8 @@ public override async Task Edit_single_property_collection_of_nullable_int32() AssertSql( """ -@p0='[null,77]' (Nullable = false) (Size = 4000) -@p1='[null,-2147483648,0,null,2147483647,null,77,null]' (Nullable = false) (Size = 4000) +@p0='[null,77]' (Nullable = false) (Size = 9) +@p1='[null,-2147483648,0,null,2147483647,null,77,null]' (Nullable = false) (Size = 49) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1959,8 +1959,8 @@ public override async Task Edit_single_property_collection_of_enum() AssertSql( """ -@p0='[-3]' (Nullable = false) (Size = 4000) -@p1='[-3]' (Nullable = false) (Size = 4000) +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-3]' (Nullable = false) (Size = 4) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -1983,8 +1983,8 @@ public override async Task Edit_single_property_collection_of_enum_with_int_conv AssertSql( """ -@p0='[-3]' (Nullable = false) (Size = 4000) -@p1='[-3]' (Nullable = false) (Size = 4000) +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-3]' (Nullable = false) (Size = 4) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -2007,8 +2007,8 @@ public override async Task Edit_single_property_collection_of_nullable_enum() AssertSql( """ -@p0='[-3]' (Nullable = false) (Size = 4000) -@p1='[-3]' (Nullable = false) (Size = 4000) +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-3]' (Nullable = false) (Size = 4) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -2055,8 +2055,8 @@ public override async Task Edit_single_property_collection_of_nullable_enum_with AssertSql( """ -@p0='[-1,null,-7,2]' (Nullable = false) (Size = 4000) -@p1='[-1,-3,-7,2]' (Nullable = false) (Size = 4000) +@p0='[-1,null,-7,2]' (Nullable = false) (Size = 14) +@p1='[-1,-3,-7,2]' (Nullable = false) (Size = 12) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -2103,8 +2103,8 @@ public override async Task Edit_single_property_collection_of_nullable_enum_with AssertSql( """ -@p0='[-3]' (Nullable = false) (Size = 4000) -@p1='[-1]' (Nullable = false) (Size = 4000) +@p0='[-3]' (Nullable = false) (Size = 4) +@p1='[-1]' (Nullable = false) (Size = 4) @p2='1' SET IMPLICIT_TRANSACTIONS OFF; @@ -2419,6 +2419,13 @@ public override async Task Add_and_update_nested_optional_primitive_collection(b _ => "1557" }; + string updateParameterSize = value switch + { + true => "4000", + false => "5", + _ => "2" + }; + string updateParameter = value switch { true => "NULL", @@ -2467,7 +2474,7 @@ FROM [JsonEntitiesAllTypes] AS [j] """, // -"@p0=" + updateParameter + @" (Nullable = false) (Size = 4000) +"@p0=" + updateParameter + @" (Nullable = false) (Size = " + updateParameterSize + @") @p1='7624' SET IMPLICIT_TRANSACTIONS OFF;