diff --git a/src/EFCore.Sqlite.Core/Metadata/Internal/SqliteAnnotationProvider.cs b/src/EFCore.Sqlite.Core/Metadata/Internal/SqliteAnnotationProvider.cs index bd4b72dd544..faf81efc55b 100644 --- a/src/EFCore.Sqlite.Core/Metadata/Internal/SqliteAnnotationProvider.cs +++ b/src/EFCore.Sqlite.Core/Metadata/Internal/SqliteAnnotationProvider.cs @@ -1,6 +1,7 @@ // 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.Metadata.Internal; using Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal; namespace Microsoft.EntityFrameworkCore.Sqlite.Metadata.Internal; @@ -47,24 +48,28 @@ public override IEnumerable For(IRelationalModel model, bool design /// public override IEnumerable For(IColumn column, bool designTime) { - // Model validation ensures that these facets are the same on all mapped properties - var property = column.PropertyMappings.First().Property; - // Only return auto increment for integer single column primary key - var primaryKey = property.DeclaringEntityType.FindPrimaryKey(); - if (primaryKey != null - && primaryKey.Properties.Count == 1 - && primaryKey.Properties[0] == property - && property.ValueGenerated == ValueGenerated.OnAdd - && property.ClrType.UnwrapNullableType().IsInteger() - && !HasConverter(property)) + // JSON columns have no property mappings so all annotations that rely on property mappings should be skipped for them + if (column is not JsonColumn) { - yield return new Annotation(SqliteAnnotationNames.Autoincrement, true); - } + // Model validation ensures that these facets are the same on all mapped properties + var property = column.PropertyMappings.First().Property; + // Only return auto increment for integer single column primary key + var primaryKey = property.DeclaringEntityType.FindPrimaryKey(); + if (primaryKey != null + && primaryKey.Properties.Count == 1 + && primaryKey.Properties[0] == property + && property.ValueGenerated == ValueGenerated.OnAdd + && property.ClrType.UnwrapNullableType().IsInteger() + && !HasConverter(property)) + { + yield return new Annotation(SqliteAnnotationNames.Autoincrement, true); + } - var srid = property.GetSrid(); - if (srid != null) - { - yield return new Annotation(SqliteAnnotationNames.Srid, srid); + var srid = property.GetSrid(); + if (srid != null) + { + yield return new Annotation(SqliteAnnotationNames.Srid, srid); + } } } diff --git a/src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs b/src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs index 347b66fae15..d9c67ab2fc1 100644 --- a/src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs +++ b/src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs @@ -73,6 +73,14 @@ public static string InvalidMigrationOperation(object? operation) public static string MigrationScriptGenerationNotSupported => GetString("MigrationScriptGenerationNotSupported"); + /// + /// JSON array element can only be accessed using constant value for the array index. Non-constant value is being used in PATH for JSON column '{jsonColumnName}'. + /// + public static string NonConstantJsonArrayIndexNotSupported(object? jsonColumnName) + => string.Format( + GetString("NonConstantJsonArrayIndexNotSupported", nameof(jsonColumnName)), + jsonColumnName); + /// /// SQLite does not support expressions of type '{type}' in ORDER BY clauses. Convert the values to a supported type, or use LINQ to Objects to order the results on the client side. /// diff --git a/src/EFCore.Sqlite.Core/Properties/SqliteStrings.resx b/src/EFCore.Sqlite.Core/Properties/SqliteStrings.resx index 681c42f2ce3..9c8edc26314 100644 --- a/src/EFCore.Sqlite.Core/Properties/SqliteStrings.resx +++ b/src/EFCore.Sqlite.Core/Properties/SqliteStrings.resx @@ -198,6 +198,9 @@ Generating idempotent scripts for migrations is not currently supported for SQLite. See http://go.microsoft.com/fwlink/?LinkId=723262 for more information and examples. + + JSON array element can only be accessed using constant value for the array index. Non-constant value is being used in PATH for JSON column '{jsonColumnName}'. + SQLite does not support expressions of type '{type}' in ORDER BY clauses. Convert the values to a supported type, or use LINQ to Objects to order the results on the client side. diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs index 7316f6fb164..e0e67021aef 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs @@ -117,4 +117,70 @@ private Expression VisitRegexp(RegexpExpression regexpExpression) return regexpExpression; } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExpression) + { + if (jsonScalarExpression.Path.Count == 1 + && jsonScalarExpression.Path[0].ToString() == "$") + { + Visit(jsonScalarExpression.JsonColumn); + + return jsonScalarExpression; + } + + // TODO: need casts? + Sql.Append("json_extract("); + + Visit(jsonScalarExpression.JsonColumn); + + Sql.Append(",'"); + foreach (var pathSegment in jsonScalarExpression.Path) + { + if (pathSegment.PropertyName != null) + { + Sql.Append((pathSegment.PropertyName == "$" ? "" : ".") + pathSegment.PropertyName); + } + + if (pathSegment.ArrayIndex != null) + { + Sql.Append("["); + + if (pathSegment.ArrayIndex is SqlConstantExpression) + { + Visit(pathSegment.ArrayIndex); + } + else + { + Sql.Append("' + "); + Visit(pathSegment.ArrayIndex); + Sql.Append(" + '"); + //throw new InvalidOperationException("TODO"); + //Sql.Append("' + CAST("); + //Visit(pathSegment.ArrayIndex); + //Sql.Append(" AS "); + //Sql.Append(_typeMappingSource.GetMapping(typeof(string)).StoreType); + //Sql.Append(") + '"); + } + + Sql.Append("]"); + } + } + + Sql.Append("')"); + + //if (jsonScalarExpression.TypeMapping is not SqlServerJsonTypeMapping and not StringTypeMapping) + //{ + // Sql.Append(" AS "); + // Sql.Append(jsonScalarExpression.TypeMapping!.StoreType); + // Sql.Append(")"); + //} + + return jsonScalarExpression; + } } diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryTranslationPostprocessor.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryTranslationPostprocessor.cs index 74095a2beb9..6bb43cf0482 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryTranslationPostprocessor.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryTranslationPostprocessor.cs @@ -14,7 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Sqlite.Query.Internal; /// public class SqliteQueryTranslationPostprocessor : RelationalQueryTranslationPostprocessor { - private readonly ApplyValidatingVisitor _applyValidator = new(); + private readonly ValidatingVisitor _validator = new(); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -39,12 +39,12 @@ public SqliteQueryTranslationPostprocessor( public override Expression Process(Expression query) { var result = base.Process(query); - _applyValidator.Visit(result); + _validator.Visit(result); return result; } - private sealed class ApplyValidatingVisitor : ExpressionVisitor + private sealed class ValidatingVisitor : ExpressionVisitor { protected override Expression VisitExtension(Expression extensionExpression) { @@ -62,6 +62,14 @@ protected override Expression VisitExtension(Expression extensionExpression) throw new InvalidOperationException(SqliteStrings.ApplyNotSupported); } + if (extensionExpression is JsonScalarExpression jsonScalarExpression + && jsonScalarExpression.Path.Any(x => x.ArrayIndex is not null and not SqlConstantExpression)) + { + throw new InvalidOperationException( + SqliteStrings.NonConstantJsonArrayIndexNotSupported( + jsonScalarExpression.JsonColumn.Name)); + } + return base.VisitExtension(extensionExpression); } } diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteJsonTypeMapping.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteJsonTypeMapping.cs new file mode 100644 index 00000000000..30e9a6027cf --- /dev/null +++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteJsonTypeMapping.cs @@ -0,0 +1,95 @@ +// 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.Json; + +namespace Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal; + +/// +/// 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 class SqliteJsonTypeMapping : JsonTypeMapping +{ + private static readonly MethodInfo _getStringMethod + = typeof(DbDataReader).GetRuntimeMethod(nameof(DbDataReader.GetString), new[] { typeof(int) })!; + + private static readonly MethodInfo _jsonDocumentParseMethod + = typeof(JsonDocument).GetRuntimeMethod(nameof(JsonDocument.Parse), new[] { typeof(string), typeof(JsonDocumentOptions) })!; + + private static readonly MemberInfo _jsonDocumentRootElementMember + = typeof(JsonDocument).GetRuntimeProperty(nameof(JsonDocument.RootElement))!; + + /// + /// Initializes a new instance of the class. + /// + /// The name of the database type. + public SqliteJsonTypeMapping(string storeType) + : base(storeType, typeof(JsonElement), System.Data.DbType.String) + { + } + + /// + /// 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 SqliteJsonTypeMapping(RelationalTypeMappingParameters parameters) + : base(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. + /// + public override MethodInfo GetDataReaderMethod() + => _getStringMethod; + + /// + /// 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 override Expression CustomizeDataReaderExpression(Expression expression) + => Expression.MakeMemberAccess( + Expression.Call( + _jsonDocumentParseMethod, + expression, + Expression.Default(typeof(JsonDocumentOptions))), + _jsonDocumentRootElementMember); + + /// + /// 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 string GenerateNonNullSqlLiteral(object value) + => $"'{EscapeSqlLiteral(JsonSerializer.Serialize(value))}'"; + + /// + /// 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 virtual string EscapeSqlLiteral(string literal) + => literal.Replace("'", "''"); + + /// + /// 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 RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters) + => new SqliteJsonTypeMapping(parameters); +} diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs index 2dc07d88c8c..08ec4f9e887 100644 --- a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.cs +++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteTypeMappingSource.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 System.Text.Json; + namespace Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal; /// @@ -80,7 +82,8 @@ private static readonly HashSet SpatialiteTypes { typeof(decimal), new SqliteDecimalTypeMapping(TextTypeName) }, { typeof(double), Real }, { typeof(float), new FloatTypeMapping(RealTypeName) }, - { typeof(Guid), new SqliteGuidTypeMapping(TextTypeName) } + { typeof(Guid), new SqliteGuidTypeMapping(TextTypeName) }, + { typeof(JsonElement), new SqliteJsonTypeMapping(TextTypeName) } }; private readonly Dictionary _storeTypeMappings = new(StringComparer.OrdinalIgnoreCase) diff --git a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs index ce63c8289e2..7318c7d3408 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryAdHocTestBase.cs @@ -19,7 +19,10 @@ protected override string StoreName [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( + onConfiguring: OnConfiguring29219, + seed: Seed29219); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.Where(x => x.Id == 3); @@ -38,7 +41,10 @@ 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( + onConfiguring: OnConfiguring29219, + seed: Seed29219); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.OrderBy(x => x.Id).Select(x => x.Reference.NullableScalar); @@ -54,6 +60,10 @@ public virtual async Task Can_project_nullable_json_property_when_the_element_in } } + protected virtual void OnConfiguring29219(DbContextOptionsBuilder builder) + { + } + protected abstract void Seed29219(MyContext29219 ctx); protected class MyContext29219 : DbContext @@ -94,7 +104,10 @@ public class MyJsonEntity29219 [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( + onConfiguring: OnConfiguringArrayOfPrimitives, + seed: SeedArrayOfPrimitives); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.OrderBy(x => x.Id).Select(x => new { x.Reference.IntArray, x.Reference.ListOfString }); @@ -115,7 +128,10 @@ 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( + onConfiguring: OnConfiguringArrayOfPrimitives, + 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 }); @@ -136,7 +152,10 @@ 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( + onConfiguring: OnConfiguringArrayOfPrimitives, + seed: SeedArrayOfPrimitives); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.OrderBy(x => x.Id).Select(x => new @@ -155,7 +174,10 @@ 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( + onConfiguring: OnConfiguringArrayOfPrimitives, + seed: SeedArrayOfPrimitives); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.Where(x => x.Reference.IntArray[0] == 1); @@ -175,7 +197,10 @@ 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( + onConfiguring: OnConfiguringArrayOfPrimitives, + seed: SeedArrayOfPrimitives); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.Where(x => x.Reference.ListOfString[1] == "Bar"); @@ -195,7 +220,10 @@ 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( + onConfiguring: OnConfiguringArrayOfPrimitives, + seed: SeedArrayOfPrimitives); + using (var context = contextFactory.CreateContext()) { var query = context.Entities.Where(x => x.Reference.IntArray.AsQueryable().ElementAt(0) == 1 @@ -215,6 +243,10 @@ public virtual async Task Predicate_based_on_element_of_json_array_of_primitives protected abstract void SeedArrayOfPrimitives(MyContextArrayOfPrimitives ctx); + protected virtual void OnConfiguringArrayOfPrimitives(DbContextOptionsBuilder builder) + { + } + protected class MyContextArrayOfPrimitives : DbContext { public MyContextArrayOfPrimitives(DbContextOptions options) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/JsonQueryAdHocSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/JsonQueryAdHocSqliteTest.cs new file mode 100644 index 00000000000..558d2637418 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Query/JsonQueryAdHocSqliteTest.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query; + +public class JsonQueryAdHocSqliteTest : JsonQueryAdHocTestBase +{ + public JsonQueryAdHocSqliteTest(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + } + + protected override ITestStoreFactory TestStoreFactory + => SqliteTestStoreFactory.Instance; + + // issue #26708 + protected override void OnConfiguring29219(DbContextOptionsBuilder builder) + => base.AddOptions(builder.ConfigureWarnings(b => b.Ignore(SqliteEventId.CompositeKeyWithValueGeneration))); + + protected override void Seed29219(MyContext29219 ctx) + { + var entity1 = new MyEntity29219 + { + Id = 1, + Reference = new MyJsonEntity29219 { NonNullableScalar = 10, NullableScalar = 11 }, + Collection = new List + { + new MyJsonEntity29219 { NonNullableScalar = 100, NullableScalar = 101 }, + new MyJsonEntity29219 { NonNullableScalar = 200, NullableScalar = 201 }, + new MyJsonEntity29219 { NonNullableScalar = 300, NullableScalar = null }, + } + }; + + var entity2 = new MyEntity29219 + { + Id = 2, + Reference = new MyJsonEntity29219 { NonNullableScalar = 20, NullableScalar = null }, + Collection = new List + { + new MyJsonEntity29219 { NonNullableScalar = 1001, NullableScalar = null }, + } + }; + + ctx.Entities.AddRange(entity1, entity2); + ctx.SaveChanges(); + + ctx.Database.ExecuteSqlRaw(@"INSERT INTO ""Entities"" (""Id"", ""Reference"", ""Collection"") +VALUES(3, '{{ ""NonNullableScalar"" : 30 }}', '[{{ ""NonNullableScalar"" : 10001 }}]')"); + } + + // issue #26708 + protected override void OnConfiguringArrayOfPrimitives(DbContextOptionsBuilder builder) + => base.AddOptions(builder.ConfigureWarnings(b => b.Ignore(SqliteEventId.CompositeKeyWithValueGeneration))); + + protected override void SeedArrayOfPrimitives(MyContextArrayOfPrimitives ctx) + { + var entity1 = new MyEntityArrayOfPrimitives + { + Id = 1, + Reference = new MyJsonEntityArrayOfPrimitives + { + IntArray = new int[] { 1, 2, 3 }, + ListOfString = new List { "Foo", "Bar", "Baz" } + }, + Collection = new List + { + new MyJsonEntityArrayOfPrimitives + { + IntArray = new int[] { 111, 112, 113 }, + ListOfString = new List { "Foo11", "Bar11" } + }, + new MyJsonEntityArrayOfPrimitives + { + IntArray = new int[] { 211, 212, 213 }, + ListOfString = new List { "Foo12", "Bar12" } + }, + } + }; + + var entity2 = new MyEntityArrayOfPrimitives + { + Id = 2, + Reference = new MyJsonEntityArrayOfPrimitives + { + IntArray = new int[] { 10, 20, 30 }, + ListOfString = new List { "A", "B", "C" } + }, + Collection = new List + { + new MyJsonEntityArrayOfPrimitives + { + IntArray = new int[] { 110, 120, 130 }, + ListOfString = new List { "A1", "Z1" } + }, + new MyJsonEntityArrayOfPrimitives + { + IntArray = new int[] { 210, 220, 230 }, + ListOfString = new List { "A2", "Z2" } + }, + } + }; + + ctx.Entities.AddRange(entity1, entity2); + ctx.SaveChanges(); + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/JsonQuerySqliteFixture.cs b/test/EFCore.Sqlite.FunctionalTests/Query/JsonQuerySqliteFixture.cs new file mode 100644 index 00000000000..a62a5afd707 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Query/JsonQuerySqliteFixture.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query; + +public class JsonQuerySqliteFixture : JsonQueryFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory + => SqliteTestStoreFactory.Instance; + + + // issue #26708 + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + => base.AddOptions(builder.ConfigureWarnings(b => b.Ignore(SqliteEventId.CompositeKeyWithValueGeneration))); +} diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/JsonQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/JsonQuerySqliteTest.cs new file mode 100644 index 00000000000..3206b9936c9 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Query/JsonQuerySqliteTest.cs @@ -0,0 +1,1987 @@ +// 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.Sqlite; +using Microsoft.EntityFrameworkCore.Sqlite.Internal; +using Microsoft.EntityFrameworkCore.TestModels.JsonQuery; + +namespace Microsoft.EntityFrameworkCore.Query; + +public class JsonQuerySqliteTest : JsonQueryTestBase +{ + public JsonQuerySqliteTest(JsonQuerySqliteFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + public override async Task Project_json_entity_FirstOrDefault_subquery(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Project_json_entity_FirstOrDefault_subquery(async))) + .Message); + + public override async Task Project_json_entity_FirstOrDefault_subquery_deduplication(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Project_json_entity_FirstOrDefault_subquery_deduplication(async))) + .Message); + + public override async Task Project_json_entity_FirstOrDefault_subquery_deduplication_and_outer_reference(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Project_json_entity_FirstOrDefault_subquery_deduplication_and_outer_reference(async))) + .Message); + + public override async Task Project_json_entity_FirstOrDefault_subquery_deduplication_outer_reference_and_pruning(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Project_json_entity_FirstOrDefault_subquery_deduplication_outer_reference_and_pruning(async))) + .Message); + + public override async Task Json_collection_element_access_in_predicate_nested_mix(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_predicate_nested_mix(async))) + .Message); + + public override async Task Json_collection_element_access_in_predicate_using_column(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_predicate_using_column(async))) + .Message); + + public override async Task Json_collection_element_access_in_predicate_using_complex_expression1(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_predicate_using_complex_expression1(async))) + .Message); + + public override async Task Json_collection_element_access_in_predicate_using_complex_expression2(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_predicate_using_complex_expression2(async))) + .Message); + + public override async Task Json_collection_element_access_in_predicate_using_variable(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_predicate_using_variable(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_nested(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_nested(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_nested_project_collection(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_nested_project_collection(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_nested_project_collection_anonymous_projection(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_nested_project_collection_anonymous_projection(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_nested_project_reference(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_nested_project_reference(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_nested_project_scalar(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_nested_project_scalar(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_using_column(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_using_column(async))) + .Message); + + public override async Task Json_collection_element_access_in_projection_using_parameter(bool async) + => Assert.Equal( + SqliteStrings.NonConstantJsonArrayIndexNotSupported("OwnedCollectionRoot"), + (await Assert.ThrowsAsync( + () => base.Json_collection_element_access_in_projection_using_parameter(async))) + .Message); + +// 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_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_duplicated(bool async) +// { +// await base.Basic_json_projection_owned_reference_duplicated(async); + +// AssertSql( +//""" +//SELECT "j"."OwnedReferenceRoot", "j"."Id" +//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_reference_branch(bool async) +// { +// await base.Basic_json_projection_owned_reference_branch(async); + +// AssertSql( +//""" +//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( +//""" +//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_extract("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], JSON_VALUE([j].[OwnedReferenceRoot],'$.OwnedReferenceBranch.Enum') 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],'$.CustomEnum') 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", "j"."EntityBasicId", "j"."Name", "j"."OwnedCollectionRoot", "j"."OwnedReferenceRoot", json_extract("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 [j].[OwnedReferenceRoot], [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot] +//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 ef_compare(json_extract("j"."OwnedReferenceRoot",'$.OwnedReferenceBranch.Fraction'), '20.5') < 0 +//"""); +// } + +// public override async Task Json_subquery_property_pushdown_length(bool async) +// { +// await base.Json_subquery_property_pushdown_length(async); + +// AssertSql( +//""" +//@__p_0='3' + +//SELECT length("t0"."c") +//FROM ( +// SELECT DISTINCT "t"."c" +// FROM ( +// SELECT json_extract("j"."OwnedReferenceRoot",'$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') AS "c" +// FROM "JsonEntitiesBasic" AS "j" +// ORDER BY "j"."Id" +// LIMIT @__p_0 +// ) AS "t" +//) AS "t0" +//"""); +// } + +// public override async Task Json_subquery_reference_pushdown_reference(bool async) +// { +// await base.Json_subquery_reference_pushdown_reference(async); + +// AssertSql( +//""" +//@__p_0='10' + +//SELECT JSON_QUERY([t0].[c],'$.OwnedReferenceBranch'), [t0].[Id] +//FROM ( +// SELECT DISTINCT [t].[c] AS [c], [t].[Id] +// FROM ( +// SELECT TOP(@__p_0) [j].[OwnedReferenceRoot] AS [c], [j].[Id] +// FROM [JsonEntitiesBasic] AS [j] +// ORDER BY [j].[Id] +// ) AS [t] +//) AS [t0] +//"""); +// } + +// 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) +// { +// await base.Json_subquery_reference_pushdown_reference_pushdown_reference(async); + +// AssertSql( +//""" +//@__p_0='10' + +//SELECT json_extract("t2"."c",'$.OwnedReferenceLeaf'), "t2"."Id" +//FROM ( +// SELECT DISTINCT "t1"."c" AS "c", "t1"."Id" +// FROM ( +// SELECT json_extract("t0"."c",'$.OwnedReferenceBranch') AS "c", "t0"."Id" +// FROM ( +// SELECT DISTINCT "t"."c" AS "c", "t"."Id", "t"."c" AS "c0" +// FROM ( +// SELECT "j"."OwnedReferenceRoot" AS "c", "j"."Id" +// FROM "JsonEntitiesBasic" AS "j" +// ORDER BY "j"."Id" +// LIMIT @__p_0 +// ) AS "t" +// ) AS "t0" +// ORDER BY json_extract("t0"."c0",'$.Name') +// LIMIT @__p_0 +// ) AS "t1" +//) AS "t2" +//"""); +// } + +// public override async Task Json_subquery_reference_pushdown_reference_pushdown_collection(bool async) +// { +// await base.Json_subquery_reference_pushdown_reference_pushdown_collection(async); + +// AssertSql( +//""" +//@__p_0='10' + +//SELECT json_extract("t2"."c",'$.OwnedCollectionLeaf'), "t2"."Id" +//FROM ( +// SELECT DISTINCT "t1"."c" AS "c", "t1"."Id" +// FROM ( +// SELECT json_extract("t0"."c",'$.OwnedReferenceBranch') AS "c", "t0"."Id" +// FROM ( +// SELECT DISTINCT "t"."c" AS "c", "t"."Id", "t"."c" AS "c0" +// FROM ( +// SELECT "j"."OwnedReferenceRoot" AS "c", "j"."Id" +// FROM "JsonEntitiesBasic" AS "j" +// ORDER BY "j"."Id" +// LIMIT @__p_0 +// ) AS "t" +// ) AS "t0" +// ORDER BY json_extract("t0"."c0",'$.Name') +// LIMIT @__p_0 +// ) AS "t1" +//) AS "t2" +//"""); +// } + +// public override async Task Json_subquery_reference_pushdown_property(bool async) +// { +// await base.Json_subquery_reference_pushdown_property(async); + +// AssertSql( +//""" +//@__p_0='10' + +//SELECT JSON_VALUE([t0].[c],'$.SomethingSomething') +//FROM ( +// SELECT DISTINCT [t].[c] AS [c], [t].[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 [t] +//) AS [t0] +//"""); +// } + +// 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_extract("j"."json_reference_custom_naming",'$.CustomOwnedReferenceBranch'), "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],'$.CustomOwnedReferenceBranch.CustomFraction') 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], JSON_VALUE([j].[json_reference_custom_naming],'$.CustomName'), CAST(JSON_VALUE([j].[json_reference_custom_naming],'$.CustomOwnedReferenceBranch.CustomFraction') 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] +//"""); +// } + +// 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" +//"""); +// } + +// 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].[EntityBasicId], [j0].[Name], [j0].[OwnedCollectionRoot], [j0].[OwnedReferenceRoot] +//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"."EntityBasicId", "j"."Name", "j"."OwnedCollectionRoot", "j"."OwnedReferenceRoot", "j0"."Name", "j0"."OwnedCollection" +//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 [t].[c], [t].[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 [t] +//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 json_extract("j0"."OwnedReferenceRoot",'$.OwnedReferenceBranch.Date') +// FROM "JsonEntitiesBasic" AS "j0" +// ORDER BY "j0"."Id" +// LIMIT 1) +//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 [t].[c], [t].[Id], [t].[c0], [t].[Id0], [t].[c1], [t].[c2], [t].[c3], [t].[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], JSON_VALUE([j].[OwnedReferenceRoot],'$.OwnedReferenceBranch.Enum') AS [c3], 1 AS [c4] +// FROM [JsonEntitiesBasic] AS [j0] +// ORDER BY [j0].[Id] +//) AS [t] +//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 [t].[c], [t].[Id], [t].[c0], [t].[Id0], [t].[c1], [t].[c2], [t].[c3], [t].[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], JSON_VALUE([j].[OwnedReferenceRoot],'$.OwnedReferenceBranch.Enum') AS [c3], 1 AS [c4] +// FROM [JsonEntitiesBasic] AS [j0] +// ORDER BY [j0].[Id] +//) AS [t] +//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 [t].[c], [t].[Id], [t].[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 [t] +//ORDER BY [j].[Id] +//"""); +// } + +// 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"."Discriminator", "j"."Name", "j"."Fraction", "j"."CollectionOnBase", "j"."ReferenceOnBase", "j"."CollectionOnDerived", "j"."ReferenceOnDerived" +//FROM "JsonEntitiesInheritance" AS "j" +//WHERE "j"."Discriminator" = 'JsonEntityInheritanceDerived' +//"""); +// } + +// public override async Task Json_entity_backtracking(bool async) +// { +// await base.Json_entity_backtracking(async); + +// AssertSql( +// @""); +// } + +// public override async Task Json_collection_element_access_in_projection_basic(bool async) +// { +// await base.Json_collection_element_access_in_projection_basic(async); + +// AssertSql( +//""" +//SELECT json_extract("j"."OwnedCollectionRoot",'$[1]'), "j"."Id" +//FROM "JsonEntitiesBasic" AS "j" +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_using_ElementAt(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_ElementAt(async); + +// AssertSql( +//""" +//SELECT JSON_QUERY([j].[OwnedCollectionRoot],'$[1]'), [j].[Id] +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_using_ElementAtOrDefault(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_ElementAtOrDefault(async); + +// AssertSql( +//""" +//SELECT json_extract("j"."OwnedCollectionRoot",'$[1]'), "j"."Id" +//FROM "JsonEntitiesBasic" AS "j" +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_project_collection(bool async) +// { +// await base.Json_collection_element_access_in_projection_project_collection(async); + +// AssertSql( +//""" +//SELECT json_extract("j"."OwnedCollectionRoot",'$[1].OwnedCollectionBranch'), "j"."Id" +//FROM "JsonEntitiesBasic" AS "j" +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_using_ElementAt_project_collection(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_ElementAt_project_collection(async); + +// AssertSql( +//""" +//SELECT JSON_QUERY([j].[OwnedCollectionRoot],'$[1].OwnedCollectionBranch'), [j].[Id] +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_using_ElementAtOrDefault_project_collection(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_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_element_access_in_projection_using_parameter(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_projection_using_column(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_projection_using_untranslatable_client_method(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_untranslatable_client_method(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_in_projection_using_untranslatable_client_method2(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_untranslatable_client_method2(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_outside_bounds(bool async) +// { +// await base.Json_collection_element_access_outside_bounds(async); + +// AssertSql( +//""" +//SELECT json_extract("j"."OwnedCollectionRoot",'$[25]'), "j"."Id" +//FROM "JsonEntitiesBasic" AS "j" +//"""); +// } + +// public override async Task Json_collection_element_access_outside_bounds_with_property_access(bool async) +// { +// await base.Json_collection_element_access_outside_bounds_with_property_access(async); + +// AssertSql( +//""" +//SELECT json_extract("j"."OwnedCollectionRoot",'$[25].Number') +//FROM "JsonEntitiesBasic" AS "j" +//ORDER BY "j"."Id" +//"""); +// } + +// //[SqlServerCondition(SqlServerCondition.SupportsJsonPathExpressions)] +// public override async Task Json_collection_element_access_in_projection_nested(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_projection_nested_project_scalar(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_projection_nested_project_reference(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_projection_nested_project_collection(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_projection_nested_project_collection_anonymous_projection(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_predicate_using_constant(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_predicate_using_variable(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_predicate_using_column(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_predicate_using_complex_expression1(bool async) +// { +// await base.Json_collection_element_access_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_element_access_in_predicate_using_complex_expression2(bool async) +// { +// await base.Json_collection_element_access_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([j].[Id]) +// FROM [JsonEntitiesBasic] AS [j]) AS nvarchar(max)) + '].Name') = N'e1_c2' +//"""); +// } + +// public override async Task Json_collection_element_access_in_predicate_using_ElementAt(bool async) +// { +// await base.Json_collection_element_access_in_predicate_using_ElementAt(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_element_access_in_predicate_nested_mix(bool async) +// { +// await base.Json_collection_element_access_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_element_access_manual_Element_at_and_pushdown(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_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_element_access_manual_Element_at_and_pushdown_negative(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_and_pushdown_negative(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_manual_Element_at_and_pushdown_negative2(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_and_pushdown_negative2(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_manual_Element_at_and_pushdown_negative3(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_and_pushdown_negative3(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_manual_Element_at_and_pushdown_negative4(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_and_pushdown_negative4(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_manual_Element_at_and_pushdown_negative5(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_and_pushdown_negative5(async); + +// AssertSql(); +// } + +// public override async Task Json_collection_element_access_manual_Element_at_and_pushdown_negative6(bool async) +// { +// await base.Json_collection_element_access_manual_Element_at_and_pushdown_negative6(async); + +// AssertSql(); +// } + +// 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]') +//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], [j].[OwnedReferenceRoot], @__prm_0 +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// 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'), [j].[Id], @__prm_0 +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_using_constant_when_owner_is_present(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_constant_when_owner_is_present(async); + +// AssertSql( +//""" +//SELECT "j"."Id", "j"."EntityBasicId", "j"."Name", "j"."OwnedCollectionRoot", "j"."OwnedReferenceRoot" +//FROM "JsonEntitiesBasic" AS "j" +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_using_parameter_when_owner_is_present(bool async) +// { +// await base.Json_collection_element_access_in_projection_using_parameter_when_owner_is_present(async); + +// AssertSql( +//""" +//@__prm_0='1' + +//SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], @__prm_0 +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_after_collection_element_access_in_projection_using_constant_when_owner_is_present(bool async) +// { +// await base.Json_collection_after_collection_element_access_in_projection_using_constant_when_owner_is_present(async); + +// AssertSql( +//""" +//SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_after_collection_element_access_in_projection_using_parameter_when_owner_is_present(bool async) +// { +// await base.Json_collection_after_collection_element_access_in_projection_using_parameter_when_owner_is_present(async); + +// AssertSql( +//""" +//@__prm_0='1' + +//SELECT "j"."Id", "j"."EntityBasicId", "j"."Name", "j"."OwnedCollectionRoot", "j"."OwnedReferenceRoot", @__prm_0 +//FROM "JsonEntitiesBasic" AS "j" +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_when_owner_is_present_misc1(bool async) +// { +// await base.Json_collection_element_access_in_projection_when_owner_is_present_misc1(async); + +// AssertSql( +//""" +//@__prm_0='1' + +//SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], @__prm_0 +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_when_owner_is_present_misc2(bool async) +// { +// await base.Json_collection_element_access_in_projection_when_owner_is_present_misc2(async); + +// AssertSql( +//""" +//SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot] +//FROM [JsonEntitiesBasic] AS [j] +//"""); +// } + +// public override async Task Json_collection_element_access_in_projection_when_owner_is_present_multiple(bool async) +// { +// await base.Json_collection_element_access_in_projection_when_owner_is_present_multiple(async); + +// AssertSql( +//""" +//@__prm_0='1' + +//SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], [j].[OwnedCollectionRoot], [j].[OwnedReferenceRoot], @__prm_0 +//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 json_extract("j"."OwnedReferenceRoot",'$.Number') <> length(json_extract("j"."OwnedReferenceRoot",'$.Name')) OR (json_extract("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) AND (JSON_VALUE([j].[OwnedReferenceRoot],'$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') IS NULL)) +//"""); +// } + +// public override async Task Group_by_on_json_scalar(bool async) +// { +// await base.Group_by_on_json_scalar(async); + +// AssertSql( +//""" +//SELECT [t].[Key], COUNT(*) AS [Count] +//FROM ( +// SELECT JSON_VALUE([j].[OwnedReferenceRoot],'$.Name') AS [Key] +// FROM [JsonEntitiesBasic] AS [j] +//) AS [t] +//GROUP BY [t].[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 [t].[Key], COUNT(*) AS [Count] +//FROM ( +// SELECT JSON_VALUE([j].[OwnedCollectionRoot],'$[0].Name') AS [Key] +// FROM [JsonEntitiesBasic] AS [j] +//) AS [t] +//GROUP BY [t].[Key] +//"""); +// } + +// public override async Task Group_by_First_on_json_scalar(bool async) +// { +// await base.Group_by_First_on_json_scalar(async); + +// AssertSql( +//""" +//SELECT [t1].[Id], [t1].[EntityBasicId], [t1].[Name], [t1].[c], [t1].[c0] +//FROM ( +// SELECT [t].[Key] +// FROM ( +// SELECT JSON_VALUE([j].[OwnedReferenceRoot],'$.Name') AS [Key] +// FROM [JsonEntitiesBasic] AS [j] +// ) AS [t] +// GROUP BY [t].[Key] +//) AS [t0] +//LEFT JOIN ( +// SELECT [t2].[Id], [t2].[EntityBasicId], [t2].[Name], [t2].[c] AS [c], [t2].[c0] AS [c0], [t2].[Key] +// FROM ( +// SELECT [t3].[Id], [t3].[EntityBasicId], [t3].[Name], [t3].[c] AS [c], [t3].[c0] AS [c0], [t3].[Key], ROW_NUMBER() OVER(PARTITION BY [t3].[Key] ORDER BY [t3].[Id]) AS [row] +// FROM ( +// SELECT [j0].[Id], [j0].[EntityBasicId], [j0].[Name], [j0].[OwnedCollectionRoot] AS [c], [j0].[OwnedReferenceRoot] AS [c0], JSON_VALUE([j0].[OwnedReferenceRoot],'$.Name') AS [Key] +// FROM [JsonEntitiesBasic] AS [j0] +// ) AS [t3] +// ) AS [t2] +// WHERE [t2].[row] <= 1 +//) AS [t1] ON [t0].[Key] = [t1].[Key] +//"""); +// } + +// public override async Task Group_by_FirstOrDefault_on_json_scalar(bool async) +// { +// await base.Group_by_FirstOrDefault_on_json_scalar(async); + +// AssertSql( +//""" +//SELECT [t1].[Id], [t1].[EntityBasicId], [t1].[Name], [t1].[c], [t1].[c0] +//FROM ( +// SELECT [t].[Key] +// FROM ( +// SELECT JSON_VALUE([j].[OwnedReferenceRoot],'$.Name') AS [Key] +// FROM [JsonEntitiesBasic] AS [j] +// ) AS [t] +// GROUP BY [t].[Key] +//) AS [t0] +//LEFT JOIN ( +// SELECT [t2].[Id], [t2].[EntityBasicId], [t2].[Name], [t2].[c] AS [c], [t2].[c0] AS [c0], [t2].[Key] +// FROM ( +// SELECT [t3].[Id], [t3].[EntityBasicId], [t3].[Name], [t3].[c] AS [c], [t3].[c0] AS [c0], [t3].[Key], ROW_NUMBER() OVER(PARTITION BY [t3].[Key] ORDER BY [t3].[Id]) AS [row] +// FROM ( +// SELECT [j0].[Id], [j0].[EntityBasicId], [j0].[Name], [j0].[OwnedCollectionRoot] AS [c], [j0].[OwnedReferenceRoot] AS [c0], JSON_VALUE([j0].[OwnedReferenceRoot],'$.Name') AS [Key] +// FROM [JsonEntitiesBasic] AS [j0] +// ) AS [t3] +// ) AS [t2] +// WHERE [t2].[row] <= 1 +//) AS [t1] ON [t0].[Key] = [t1].[Key] +//"""); +// } + +// 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 "t0"."Key", "t1"."Id", "t1"."EntityBasicId", "t1"."Name", "t1"."c", "t1"."c0" +//FROM ( +// SELECT "t"."Key" +// FROM ( +// SELECT json_extract("j"."OwnedReferenceRoot",'$.Name') AS "Key" +// FROM "JsonEntitiesBasic" AS "j" +// ) AS "t" +// GROUP BY "t"."Key" +//) AS "t0" +//LEFT JOIN ( +// SELECT "t2"."Id", "t2"."EntityBasicId", "t2"."Name", "t2"."c", "t2"."c0", "t2"."Key" +// FROM ( +// SELECT "t3"."Id", "t3"."EntityBasicId", "t3"."Name", "t3"."c" AS "c", "t3"."c0" AS "c0", "t3"."Key", ROW_NUMBER() OVER(PARTITION BY "t3"."Key" ORDER BY "t3"."Id") AS "row" +// FROM ( +// SELECT "j0"."Id", "j0"."EntityBasicId", "j0"."Name", "j0"."OwnedCollectionRoot" AS "c", "j0"."OwnedReferenceRoot" AS "c0", json_extract("j0"."OwnedReferenceRoot",'$.Name') AS "Key" +// FROM "JsonEntitiesBasic" AS "j0" +// ) AS "t3" +// ) AS "t2" +// WHERE 1 < "t2"."row" AND "t2"."row" <= 6 +//) AS "t1" ON "t0"."Key" = "t1"."Key" +//ORDER BY "t0"."Key", "t1"."Key", "t1"."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 json_extract("t0"."c0",'$.OwnedReferenceBranch.Enum') +// FROM ( +// SELECT "j0"."Id", "j0"."EntityBasicId", "j0"."Name", "j0"."OwnedCollectionRoot" AS "c", "j0"."OwnedReferenceRoot" AS "c0", json_extract("j0"."OwnedReferenceRoot",'$.Name') AS "Key" +// FROM "JsonEntitiesBasic" AS "j0" +// ) AS "t0" +// WHERE "t"."Key" = "t0"."Key" OR (("t"."Key" IS NULL) AND ("t0"."Key" IS NULL)) +// LIMIT 1) +//FROM ( +// SELECT json_extract("j"."OwnedReferenceRoot",'$.Name') AS "Key" +// FROM "JsonEntitiesBasic" AS "j" +//) AS "t" +//GROUP BY "t"."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_all_types_entity_projection(bool async) +// { +// await base.Json_all_types_entity_projection(async); + +// AssertSql( +//""" +//SELECT "j"."Id", "j"."Collection", "j"."Reference" +//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],'$.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], JSON_VALUE([j].[Reference],'$.TestEnum') AS [TestEnum], CAST(JSON_VALUE([j].[Reference],'$.TestEnumWithIntConverter') AS int) AS [TestEnumWithIntConverter], JSON_VALUE([j].[Reference],'$.TestNullableEnum') 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].[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].[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 CASE +// WHEN CAST(JSON_VALUE([j].[Reference],'$.TestBoolean') AS bit) = CAST(0 AS bit) THEN CAST(1 AS bit) +// ELSE CAST(0 AS bit) +//END +//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"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestDefaultString') <> 'MyDefaultStringInReference1' OR (json_extract("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].[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].[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].[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_character(bool async) +// { +// await base.Json_predicate_on_character(async); + +// AssertSql( +//""" +//SELECT [j].[Id], [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].[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].[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].[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].[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].[Collection], [j].[Reference] +//FROM [JsonEntitiesAllTypes] AS [j] +//WHERE JSON_VALUE([j].[Reference],'$.TestEnum') <> N'Two' OR (JSON_VALUE([j].[Reference],'$.TestEnum') IS NULL) +//"""); +// } + +// public override async Task Json_predicate_on_enumwithintconverter(bool async) +// { +// await base.Json_predicate_on_enumwithintconverter(async); + +// AssertSql( +//""" +//SELECT [j].[Id], [j].[Collection], [j].[Reference] +//FROM [JsonEntitiesAllTypes] AS [j] +//WHERE CAST(JSON_VALUE([j].[Reference],'$.TestEnumWithIntConverter') AS int) <> 2 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].[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].[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].[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].[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"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestNullableEnum') <> 'One' OR (json_extract("j"."Reference",'$.TestNullableEnum') IS NULL) +//"""); +// } + +// public override async Task Json_predicate_on_nullableenum2(bool async) +// { +// await base.Json_predicate_on_nullableenum2(async); + +// AssertSql( +//""" +//SELECT "j"."Id", "j"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestNullableEnum') 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"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestNullableEnumWithIntConverter') <> 1 OR (json_extract("j"."Reference",'$.TestNullableEnumWithIntConverter') IS NULL) +//"""); +// } + +// public override async Task Json_predicate_on_nullableenumwithconverter2(bool async) +// { +// await base.Json_predicate_on_nullableenumwithconverter2(async); + +// AssertSql( +//""" +//SELECT "j"."Id", "j"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestNullableEnumWithIntConverter') 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"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestNullableEnumWithConverterThatHandlesNulls') <> 'One' OR (json_extract("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].[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].[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].[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].[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"."Collection", "j"."Reference" +//FROM "JsonEntitiesAllTypes" AS "j" +//WHERE json_extract("j"."Reference",'$.TestTimeSpan') <> '03:02:00' OR (json_extract("j"."Reference",'$.TestTimeSpan') IS NULL) +//"""); +// } + +// public override async Task Json_predicate_on_unisgnedint16(bool async) +// { +// await base.Json_predicate_on_unisgnedint16(async); + +// AssertSql( +//""" +//SELECT [j].[Id], [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].[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].[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) +//"""); +// } + +// [ConditionalTheory] +// [MemberData(nameof(IsAsyncData))] +// 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] +//"""); +// } + +[ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task FromSqlInterpolated_on_entity_with_json_with_predicate(bool async) + { + var parameter = new SqliteParameter { 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(), + entryCount: 40); + + AssertSql( +""" +prm='1' (DbType = String) + +SELECT "m"."Id", "m"."EntityBasicId", "m"."Name", "m"."OwnedCollectionRoot", "m"."OwnedReferenceRoot" +FROM ( + SELECT * FROM "JsonEntitiesBasic" AS j WHERE "j"."Id" = @prm +) AS "m" +"""); + } + + // [ConditionalTheory] + // [MemberData(nameof(IsAsyncData))] + // 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_extract("m"."OwnedReferenceRoot",'$.OwnedReferenceBranch'), "m"."Id" + //FROM ( + // SELECT * FROM "JsonEntitiesBasic" AS j + //) AS "m" + //"""); + // } + + // [ConditionalTheory] + // [MemberData(nameof(IsAsyncData))] + // 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_extract("m"."OwnedReferenceRoot",'$.OwnedCollectionBranch'), "m"."Id" + //FROM ( + // SELECT * FROM "JsonEntitiesBasic" AS j + //) AS "m" + //"""); + // } + + // [ConditionalTheory] + // [MemberData(nameof(IsAsyncData))] + // 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" + //"""); + // } + + // [ConditionalTheory] + // [MemberData(nameof(IsAsyncData))] + // 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" = 'JsonEntityInheritanceDerived' + //"""); + // } + + // [ConditionalTheory] + // [MemberData(nameof(IsAsyncData))] + // 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] + //"""); + // } + + // [ConditionalTheory] + // [MemberData(nameof(IsAsyncData))] + // 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] + //"""); + //} + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.Sqlite.FunctionalTests/SqliteComplianceTest.cs b/test/EFCore.Sqlite.FunctionalTests/SqliteComplianceTest.cs index ddaf5dc308e..2ec7dcdae39 100644 --- a/test/EFCore.Sqlite.FunctionalTests/SqliteComplianceTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/SqliteComplianceTest.cs @@ -8,9 +8,7 @@ public class SqliteComplianceTest : RelationalComplianceTestBase protected override ICollection IgnoredTestBases { get; } = new HashSet { typeof(FromSqlSprocQueryTestBase<>), - typeof(JsonQueryTestBase<>), typeof(JsonUpdateTestBase<>), - typeof(JsonQueryAdHocTestBase), typeof(SqlExecutorTestBase<>), typeof(UdfDbFunctionTestBase<>), typeof(TPCRelationshipsQueryTestBase<>), // internal class is added