diff --git a/src/EFCore.Jet/Metadata/Internal/JetAnnotationProvider.cs b/src/EFCore.Jet/Metadata/Internal/JetAnnotationProvider.cs index aa6f46a..f465996 100644 --- a/src/EFCore.Jet/Metadata/Internal/JetAnnotationProvider.cs +++ b/src/EFCore.Jet/Metadata/Internal/JetAnnotationProvider.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.Extensions.DependencyInjection; namespace EntityFrameworkCore.Jet.Metadata.Internal @@ -100,6 +101,7 @@ namespace EntityFrameworkCore.Jet.Metadata.Internal } else { + if (column is JsonColumn) yield break; property = column.PropertyMappings.First().Property; if (property.DeclaringType is IEntityType entityType) { diff --git a/src/EFCore.Jet/Query/Sql/Internal/JetQuerySqlGenerator.cs b/src/EFCore.Jet/Query/Sql/Internal/JetQuerySqlGenerator.cs index cf6eb74..059401d 100644 --- a/src/EFCore.Jet/Query/Sql/Internal/JetQuerySqlGenerator.cs +++ b/src/EFCore.Jet/Query/Sql/Internal/JetQuerySqlGenerator.cs @@ -371,6 +371,17 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal return base.VisitColumn(columnExpression); } + protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExpression) + { + var path = jsonScalarExpression.Path; + if (path.Count == 0) + { + Visit(jsonScalarExpression.Json); + return jsonScalarExpression; + } + return base.VisitJsonScalar(jsonScalarExpression); + } + private bool IsNonComposedSetOperation(SelectExpression selectExpression) => selectExpression.Offset == null && selectExpression.Limit == null diff --git a/src/EFCore.Jet/Storage/Internal/JetByteArrayTypeMapping.cs b/src/EFCore.Jet/Storage/Internal/JetByteArrayTypeMapping.cs index 2725b93..b7d4104 100644 --- a/src/EFCore.Jet/Storage/Internal/JetByteArrayTypeMapping.cs +++ b/src/EFCore.Jet/Storage/Internal/JetByteArrayTypeMapping.cs @@ -7,6 +7,7 @@ using System.Text; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Json; namespace EntityFrameworkCore.Jet.Storage.Internal { @@ -29,7 +30,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal StoreTypePostfix? storeTypePostfix = null) : base( new RelationalTypeMappingParameters( - new CoreTypeMappingParameters(typeof(byte[]), null, comparer), + new CoreTypeMappingParameters(typeof(byte[]), null, comparer, jsonValueReaderWriter: JsonByteArrayReaderWriter.Instance), storeType ?? (fixedLength ? "binary" : "varbinary"), storeTypePostfix ?? StoreTypePostfix.Size, System.Data.DbType.Binary, diff --git a/src/EFCore.Jet/Storage/Internal/JetDateTimeTypeMapping.cs b/src/EFCore.Jet/Storage/Internal/JetDateTimeTypeMapping.cs index d1e34cb..3c53476 100644 --- a/src/EFCore.Jet/Storage/Internal/JetDateTimeTypeMapping.cs +++ b/src/EFCore.Jet/Storage/Internal/JetDateTimeTypeMapping.cs @@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage; namespace EntityFrameworkCore.Jet.Storage.Internal { - public class JetDateTimeTypeMapping : RelationalTypeMapping + public class JetDateTimeTypeMapping : DateTimeTypeMapping { private const int MaxDateTimeDoublePrecision = 10; private static readonly JetDecimalTypeMapping _decimalTypeMapping = new JetDecimalTypeMapping("decimal", System.Data.DbType.Decimal, 18, 10); @@ -23,7 +23,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal [NotNull] IJetOptions options, DbType? dbType = null, [CanBeNull] Type? clrType = null) - : base(storeType, clrType ?? typeof(DateTime), dbType ?? System.Data.DbType.DateTime) + : base(storeType) { _options = options; } @@ -40,13 +40,13 @@ namespace EntityFrameworkCore.Jet.Storage.Internal protected override void ConfigureParameter(DbParameter parameter) { base.ConfigureParameter(parameter); - + if (_options.EnableMillisecondsSupport && parameter.Value is DateTime dateTime) { parameter.Value = GetDateTimeDoubleValueAsDecimal(dateTime, _options.EnableMillisecondsSupport); parameter.ResetDbType(); - + // Necessary to explicitly set for OLE DB, to apply the System.Decimal value as DOUBLE to Jet. parameter.DbType = System.Data.DbType.Double; } @@ -75,7 +75,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal : "#"); literal.AppendFormat(CultureInfo.InvariantCulture, "{0:yyyy-MM-dd}", dateTime); - + var time = dateTime.TimeOfDay; if (time != TimeSpan.Zero) { @@ -94,7 +94,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal var millisecondsTicks = time.Ticks % TimeSpan.TicksPerSecond / TimeSpan.TicksPerMillisecond * TimeSpan.TicksPerMillisecond; if (millisecondsTicks > 0) { - var jetTimeDoubleFractions = Math.Round((decimal) millisecondsTicks / TimeSpan.TicksPerDay, MaxDateTimeDoublePrecision); + var jetTimeDoubleFractions = Math.Round((decimal)millisecondsTicks / TimeSpan.TicksPerDay, MaxDateTimeDoublePrecision); literal .Insert(0, "(") @@ -108,28 +108,28 @@ namespace EntityFrameworkCore.Jet.Storage.Internal } protected virtual DateTime ConvertToDateTimeCompatibleValue(object value) - => (DateTime) value; + => (DateTime)value; private static decimal GetDateTimeDoubleValueAsDecimal(DateTime dateTime, bool millisecondsSupportEnabled) { // // We are explicitly using System.Decimal here, so we get better scale results: // - + var checkDateTimeValue = CheckDateTimeValue(dateTime) - JetConfiguration.TimeSpanOffset; if (millisecondsSupportEnabled) { // Round to milliseconds. var millisecondsTicks = checkDateTimeValue.Ticks / TimeSpan.TicksPerMillisecond * TimeSpan.TicksPerMillisecond; - var result = /*Math.Round(*/(decimal) millisecondsTicks / TimeSpan.TicksPerDay/*, MaxDateTimeDoublePrecision, MidpointRounding.AwayFromZero)*/; + var result = /*Math.Round(*/(decimal)millisecondsTicks / TimeSpan.TicksPerDay/*, MaxDateTimeDoublePrecision, MidpointRounding.AwayFromZero)*/; return result; } else { // Round to seconds. var secondsTicks = checkDateTimeValue.Ticks / TimeSpan.TicksPerSecond * TimeSpan.TicksPerSecond; - var result = /*Math.Round(*/(decimal) secondsTicks / TimeSpan.TicksPerDay/*, MaxDateTimeDoublePrecision, MidpointRounding.AwayFromZero)*/; + var result = /*Math.Round(*/(decimal)secondsTicks / TimeSpan.TicksPerDay/*, MaxDateTimeDoublePrecision, MidpointRounding.AwayFromZero)*/; return result; } } diff --git a/src/EFCore.Jet/Storage/Internal/JetDecimalTypeMapping.cs b/src/EFCore.Jet/Storage/Internal/JetDecimalTypeMapping.cs index bc1f84d..d3fe3ed 100644 --- a/src/EFCore.Jet/Storage/Internal/JetDecimalTypeMapping.cs +++ b/src/EFCore.Jet/Storage/Internal/JetDecimalTypeMapping.cs @@ -3,6 +3,7 @@ using System.Data.Common; using System.Linq; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Json; namespace EntityFrameworkCore.Jet.Storage.Internal { @@ -28,7 +29,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal StoreTypePostfix storeTypePostfix = StoreTypePostfix.PrecisionAndScale) : base( new RelationalTypeMappingParameters( - new CoreTypeMappingParameters(typeof(decimal)), + new CoreTypeMappingParameters(typeof(decimal), jsonValueReaderWriter: JsonDecimalReaderWriter.Instance), storeType, storeTypePostfix, dbType) diff --git a/src/EFCore.Jet/Storage/Internal/JetJsonTypeMapping.cs b/src/EFCore.Jet/Storage/Internal/JetJsonTypeMapping.cs new file mode 100644 index 0000000..863f72b --- /dev/null +++ b/src/EFCore.Jet/Storage/Internal/JetJsonTypeMapping.cs @@ -0,0 +1,113 @@ +// 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.Common; +using System.IO; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Text.Json; +using Microsoft.EntityFrameworkCore.Storage; + +namespace EntityFrameworkCore.Jet.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 JetJsonTypeMapping : JsonTypeMapping +{ + private static readonly MethodInfo GetStringMethod + = typeof(DbDataReader).GetRuntimeMethod(nameof(DbDataReader.GetString), new[] { typeof(int) })!; + + private static readonly PropertyInfo UTF8Property + = typeof(Encoding).GetProperty(nameof(Encoding.UTF8))!; + + private static readonly MethodInfo EncodingGetBytesMethod + = typeof(Encoding).GetMethod(nameof(Encoding.GetBytes), new[] { typeof(string) })!; + + private static readonly ConstructorInfo MemoryStreamConstructor + = typeof(MemoryStream).GetConstructor(new[] { typeof(byte[]) })!; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public static JetJsonTypeMapping Default { get; } = new("longchar"); + + /// + /// 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 JetJsonTypeMapping(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. + /// + 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.New( + MemoryStreamConstructor, + Expression.Call( + Expression.Property(null, UTF8Property), + EncodingGetBytesMethod, + expression)); + + /// + /// 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 JetJsonTypeMapping(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. + /// + 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 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 override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters) + => new JetJsonTypeMapping(parameters); +} diff --git a/src/EFCore.Jet/Storage/Internal/JetStringTypeMapping.cs b/src/EFCore.Jet/Storage/Internal/JetStringTypeMapping.cs index d3c5f07..594db88 100644 --- a/src/EFCore.Jet/Storage/Internal/JetStringTypeMapping.cs +++ b/src/EFCore.Jet/Storage/Internal/JetStringTypeMapping.cs @@ -5,6 +5,7 @@ using System.Data; using System.Data.Common; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Json; namespace EntityFrameworkCore.Jet.Storage.Internal { @@ -30,12 +31,12 @@ namespace EntityFrameworkCore.Jet.Storage.Internal bool keepLineBreakCharacters = false) : this( new RelationalTypeMappingParameters( - new CoreTypeMappingParameters(typeof(string)), + new CoreTypeMappingParameters(typeof(string), jsonValueReaderWriter: JsonStringReaderWriter.Instance), storeType ?? GetStoreName(fixedLength), storeTypePostfix ?? StoreTypePostfix.Size, (fixedLength ? System.Data.DbType.StringFixedLength - : (DbType?) System.Data.DbType.String), + : (DbType?)System.Data.DbType.String), unicode, size, fixedLength), @@ -103,7 +104,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal protected override string GenerateNonNullSqlLiteral(object value) { var escaped = $"'{EscapeSqlLiteral((string)value)}'"; - + // BUG: EF Core indents idempotent scripts, which can lead to unexpected values for strings // that contain line breaks. // Tracked by: https://github.com/aspnet/EntityFrameworkCore/issues/15256 diff --git a/src/EFCore.Jet/Storage/Internal/JetTypeMappingSource.cs b/src/EFCore.Jet/Storage/Internal/JetTypeMappingSource.cs index 6dbd1d1..7091118 100644 --- a/src/EFCore.Jet/Storage/Internal/JetTypeMappingSource.cs +++ b/src/EFCore.Jet/Storage/Internal/JetTypeMappingSource.cs @@ -5,11 +5,13 @@ using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; +using System.Text.Json; using EntityFrameworkCore.Jet.Infrastructure.Internal; using EntityFrameworkCore.Jet.Internal; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.EntityFrameworkCore.Storage; namespace EntityFrameworkCore.Jet.Storage.Internal @@ -53,7 +55,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal private readonly JetStringTypeMapping _variableLengthUnicodeString = new JetStringTypeMapping("varchar", unicode: true); private readonly JetStringTypeMapping _variableLengthMaxUnicodeString = new JetStringTypeMapping("varchar(max)", unicode: true, storeTypePostfix: StoreTypePostfix.None); private readonly JetStringTypeMapping _unboundedUnicodeString = new JetStringTypeMapping("longchar", unicode: true, storeTypePostfix: StoreTypePostfix.None); - + private readonly JetJsonTypeMapping _jsonTypeMapping = new JetJsonTypeMapping("longchar"); private readonly JetGuidTypeMapping _guid = new JetGuidTypeMapping("uniqueidentifier", DbType.Guid); private readonly JetByteArrayTypeMapping _rowversion = new JetByteArrayTypeMapping("varbinary", size: 8, comparer: new ValueComparer( @@ -202,6 +204,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal {typeof(TimeSpan), _timespan}, {typeof(TimeOnly), _timeonly}, {typeof(Guid), _guid}, + { typeof(JsonElement), _jsonTypeMapping } }; // These are disallowed only if specified without any kind of length specified in parenthesis. @@ -261,7 +264,8 @@ namespace EntityFrameworkCore.Jet.Storage.Internal /// directly from your code. This API may change or be removed in future releases. /// protected override RelationalTypeMapping? FindMapping(in RelationalTypeMappingInfo mappingInfo) - => base.FindMapping(mappingInfo) ?? FindRawMapping(mappingInfo)?.Clone(mappingInfo); + => base.FindMapping(mappingInfo) + ?? FindRawMapping(mappingInfo)?.WithTypeMappingInfo(mappingInfo); /// /// This API supports the Entity Framework Core infrastructure and is not intended to be used @@ -355,23 +359,26 @@ namespace EntityFrameworkCore.Jet.Storage.Internal return _rowversion; } - var isFixedLength = mappingInfo.IsFixedLength == true; - - const int maxBinaryColumnSize = 510; - - var size = mappingInfo.Size ?? (mappingInfo.IsKeyOrIndex ? (int?)maxBinaryColumnSize : null); - if (size > maxBinaryColumnSize) + if (mappingInfo.ElementTypeMapping == null) { - size = isFixedLength ? maxBinaryColumnSize : (int?)null; + var isFixedLength = mappingInfo.IsFixedLength == true; + + const int maxBinaryColumnSize = 510; + + var size = mappingInfo.Size ?? (mappingInfo.IsKeyOrIndex ? (int?)maxBinaryColumnSize : null); + if (size > maxBinaryColumnSize) + { + size = isFixedLength ? maxBinaryColumnSize : (int?)null; + } + + return size == null + ? _unboundedBinary + : new JetByteArrayTypeMapping( + size: size, + storeType: isFixedLength + ? _fixedLengthBinary.StoreTypeNameBase + : _variableLengthBinary.StoreTypeNameBase); } - - return size == null - ? _unboundedBinary - : new JetByteArrayTypeMapping( - size: size, - storeType: isFixedLength - ? _fixedLengthBinary.StoreTypeNameBase - : _variableLengthBinary.StoreTypeNameBase); } } diff --git a/test/EFCore.Jet.FunctionalTests/JsonTypesJetTest.cs b/test/EFCore.Jet.FunctionalTests/JsonTypesJetTest.cs index 0f6729e..5817269 100644 --- a/test/EFCore.Jet.FunctionalTests/JsonTypesJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/JsonTypesJetTest.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Collections.Generic; using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; using Xunit; @@ -13,20 +14,54 @@ namespace EntityFrameworkCore.Jet.FunctionalTests; public class JsonTypesJetTest : JsonTypesRelationalTestBase { - // #25765 - the Jet type mapping source doesn't support primitive collections, so we end up with a Property - // that has no ElementType; that causes the assertion on the element nullability to fail. - public override void Can_read_write_collection_of_string_JSON_values() - => Assert.Throws(() => base.Can_read_write_collection_of_string_JSON_values()); - - // #25765 - the Jet type mapping source doesn't support primitive collections, so we end up with a Property - // that has no ElementType; that causes the assertion on the element nullability to fail. - public override void Can_read_write_collection_of_binary_JSON_values() - => Assert.Throws(() => base.Can_read_write_collection_of_binary_JSON_values()); - - // #25765 - the Jet type mapping source doesn't support primitive collections, so we end up with a Property - // that has no ElementType; that causes the assertion on the element nullability to fail. - public override void Can_read_write_collection_of_nullable_string_JSON_values() - => Assert.Throws(() => base.Can_read_write_collection_of_nullable_string_JSON_values()); + public override void Can_read_write_ulong_enum_JSON_values(EnumU64 value, string json) + { + if (value == EnumU64.Max) + { + json = """{"Prop":-1}"""; // Because ulong is converted to long on Jet + } + + base.Can_read_write_ulong_enum_JSON_values(value, json); + } + + public override void Can_read_write_nullable_ulong_enum_JSON_values(object? value, string json) + { + if (Equals(value, ulong.MaxValue)) + { + json = """{"Prop":-1}"""; // Because ulong is converted to long on Jet + } + + base.Can_read_write_nullable_ulong_enum_JSON_values(value, json); + } + + public override void Can_read_write_collection_of_ulong_enum_JSON_values() + => Can_read_and_write_JSON_value>( + nameof(EnumU64CollectionType.EnumU64), + new List + { + EnumU64.Min, + EnumU64.Max, + EnumU64.Default, + EnumU64.One, + (EnumU64)8 + }, + """{"Prop":[0,-1,0,1,8]}""", // Because ulong is converted to long on Jet + mappedCollection: true); + + public override void Can_read_write_collection_of_nullable_ulong_enum_JSON_values() + => Can_read_and_write_JSON_value>( + nameof(NullableEnumU64CollectionType.EnumU64), + new List + { + EnumU64.Min, + null, + EnumU64.Max, + EnumU64.Default, + EnumU64.One, + (EnumU64?)8 + }, + """{"Prop":[0,null,-1,0,1,8]}""", // Because ulong is converted to long on Jet + mappedCollection: true); public override void Can_read_write_point() // No built-in JSON support for spatial types in the Jet provider diff --git a/test/EFCore.Jet.FunctionalTests/Query/JsonQueryAdHocJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/JsonQueryAdHocJetTest.cs index ec00453..07f5557 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/JsonQueryAdHocJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/JsonQueryAdHocJetTest.cs @@ -43,7 +43,7 @@ public class JsonQueryAdHocJetTest : JsonQueryAdHocTestBase ctx.SaveChanges(); ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Id], [Reference], [Collection]) -VALUES(3, N'{{ ""NonNullableScalar"" : 30 }}', N'[{{ ""NonNullableScalar"" : 10001 }}]')"); +VALUES(3, '{{ ""NonNullableScalar"" : 30 }}', '[{{ ""NonNullableScalar"" : 10001 }}]')"); } protected override void Seed30028(MyContext30028 ctx) @@ -52,25 +52,25 @@ VALUES(3, N'{{ ""NonNullableScalar"" : 30 }}', N'[{{ ""NonNullableScalar"" : 100 ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Id], [Json]) VALUES( 1, -N'{{""RootName"":""e1"",""Collection"":[{{""BranchName"":""e1 c1"",""Nested"":{{""LeafName"":""e1 c1 l""}}}},{{""BranchName"":""e1 c2"",""Nested"":{{""LeafName"":""e1 c2 l""}}}}],""OptionalReference"":{{""BranchName"":""e1 or"",""Nested"":{{""LeafName"":""e1 or l""}}}},""RequiredReference"":{{""BranchName"":""e1 rr"",""Nested"":{{""LeafName"":""e1 rr l""}}}}}}')"); +'{{""RootName"":""e1"",""Collection"":[{{""BranchName"":""e1 c1"",""Nested"":{{""LeafName"":""e1 c1 l""}}}},{{""BranchName"":""e1 c2"",""Nested"":{{""LeafName"":""e1 c2 l""}}}}],""OptionalReference"":{{""BranchName"":""e1 or"",""Nested"":{{""LeafName"":""e1 or l""}}}},""RequiredReference"":{{""BranchName"":""e1 rr"",""Nested"":{{""LeafName"":""e1 rr l""}}}}}}')"); // missing collection ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Id], [Json]) VALUES( 2, -N'{{""RootName"":""e2"",""OptionalReference"":{{""BranchName"":""e2 or"",""Nested"":{{""LeafName"":""e2 or l""}}}},""RequiredReference"":{{""BranchName"":""e2 rr"",""Nested"":{{""LeafName"":""e2 rr l""}}}}}}')"); +'{{""RootName"":""e2"",""OptionalReference"":{{""BranchName"":""e2 or"",""Nested"":{{""LeafName"":""e2 or l""}}}},""RequiredReference"":{{""BranchName"":""e2 rr"",""Nested"":{{""LeafName"":""e2 rr l""}}}}}}')"); // missing optional reference ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Id], [Json]) VALUES( 3, -N'{{""RootName"":""e3"",""Collection"":[{{""BranchName"":""e3 c1"",""Nested"":{{""LeafName"":""e3 c1 l""}}}},{{""BranchName"":""e3 c2"",""Nested"":{{""LeafName"":""e3 c2 l""}}}}],""RequiredReference"":{{""BranchName"":""e3 rr"",""Nested"":{{""LeafName"":""e3 rr l""}}}}}}')"); +'{{""RootName"":""e3"",""Collection"":[{{""BranchName"":""e3 c1"",""Nested"":{{""LeafName"":""e3 c1 l""}}}},{{""BranchName"":""e3 c2"",""Nested"":{{""LeafName"":""e3 c2 l""}}}}],""RequiredReference"":{{""BranchName"":""e3 rr"",""Nested"":{{""LeafName"":""e3 rr l""}}}}}}')"); // missing required reference ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Id], [Json]) VALUES( 4, -N'{{""RootName"":""e4"",""Collection"":[{{""BranchName"":""e4 c1"",""Nested"":{{""LeafName"":""e4 c1 l""}}}},{{""BranchName"":""e4 c2"",""Nested"":{{""LeafName"":""e4 c2 l""}}}}],""OptionalReference"":{{""BranchName"":""e4 or"",""Nested"":{{""LeafName"":""e4 or l""}}}}}}')"); +'{{""RootName"":""e4"",""Collection"":[{{""BranchName"":""e4 c1"",""Nested"":{{""LeafName"":""e4 c1 l""}}}},{{""BranchName"":""e4 c2"",""Nested"":{{""LeafName"":""e4 c2 l""}}}}],""OptionalReference"":{{""BranchName"":""e4 or"",""Nested"":{{""LeafName"":""e4 or l""}}}}}}')"); } protected override void SeedArrayOfPrimitives(MyContextArrayOfPrimitives ctx) @@ -129,10 +129,10 @@ N'{{""RootName"":""e4"",""Collection"":[{{""BranchName"":""e4 c1"",""Nested"":{{ { ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Collection], [CollectionWithCtor], [Reference], [ReferenceWithCtor], [Id]) VALUES( -N'[{{""JunkReference"":{{""Something"":""SomeValue"" }},""Name"":""c11"",""JunkProperty1"":50,""Number"":11.5,""JunkCollection1"":[],""JunkCollection2"":[{{""Foo"":""junk value""}}],""NestedCollection"":[{{""DoB"":""2002-04-01T00:00:00"",""DummyProp"":""Dummy value""}},{{""DoB"":""2002-04-02T00:00:00"",""DummyReference"":{{""Foo"":5}}}}],""NestedReference"":{{""DoB"":""2002-03-01T00:00:00""}}}},{{""Name"":""c12"",""Number"":12.5,""NestedCollection"":[{{""DoB"":""2002-06-01T00:00:00""}},{{""DoB"":""2002-06-02T00:00:00""}}],""NestedDummy"":59,""NestedReference"":{{""DoB"":""2002-05-01T00:00:00""}}}}]', -N'[{{""MyBool"":true,""Name"":""c11 ctor"",""JunkReference"":{{""Something"":""SomeValue"",""JunkCollection"":[{{""Foo"":""junk value""}}]}},""NestedCollection"":[{{""DoB"":""2002-08-01T00:00:00""}},{{""DoB"":""2002-08-02T00:00:00""}}],""NestedReference"":{{""DoB"":""2002-07-01T00:00:00""}}}},{{""MyBool"":false,""Name"":""c12 ctor"",""NestedCollection"":[{{""DoB"":""2002-10-01T00:00:00""}},{{""DoB"":""2002-10-02T00:00:00""}}],""JunkCollection"":[{{""Foo"":""junk value""}}],""NestedReference"":{{""DoB"":""2002-09-01T00:00:00""}}}}]', -N'{{""Name"":""r1"",""JunkCollection"":[{{""Foo"":""junk value""}}],""JunkReference"":{{""Something"":""SomeValue"" }},""Number"":1.5,""NestedCollection"":[{{""DoB"":""2000-02-01T00:00:00"",""JunkReference"":{{""Something"":""SomeValue""}}}},{{""DoB"":""2000-02-02T00:00:00""}}],""NestedReference"":{{""DoB"":""2000-01-01T00:00:00""}}}}', -N'{{""MyBool"":true,""JunkCollection"":[{{""Foo"":""junk value""}}],""Name"":""r1 ctor"",""JunkReference"":{{""Something"":""SomeValue"" }},""NestedCollection"":[{{""DoB"":""2001-02-01T00:00:00""}},{{""DoB"":""2001-02-02T00:00:00""}}],""NestedReference"":{{""JunkCollection"":[{{""Foo"":""junk value""}}],""DoB"":""2001-01-01T00:00:00""}}}}', +'[{{""JunkReference"":{{""Something"":""SomeValue"" }},""Name"":""c11"",""JunkProperty1"":50,""Number"":11.5,""JunkCollection1"":[],""JunkCollection2"":[{{""Foo"":""junk value""}}],""NestedCollection"":[{{""DoB"":""2002-04-01T00:00:00"",""DummyProp"":""Dummy value""}},{{""DoB"":""2002-04-02T00:00:00"",""DummyReference"":{{""Foo"":5}}}}],""NestedReference"":{{""DoB"":""2002-03-01T00:00:00""}}}},{{""Name"":""c12"",""Number"":12.5,""NestedCollection"":[{{""DoB"":""2002-06-01T00:00:00""}},{{""DoB"":""2002-06-02T00:00:00""}}],""NestedDummy"":59,""NestedReference"":{{""DoB"":""2002-05-01T00:00:00""}}}}]', +'[{{""MyBool"":true,""Name"":""c11 ctor"",""JunkReference"":{{""Something"":""SomeValue"",""JunkCollection"":[{{""Foo"":""junk value""}}]}},""NestedCollection"":[{{""DoB"":""2002-08-01T00:00:00""}},{{""DoB"":""2002-08-02T00:00:00""}}],""NestedReference"":{{""DoB"":""2002-07-01T00:00:00""}}}},{{""MyBool"":false,""Name"":""c12 ctor"",""NestedCollection"":[{{""DoB"":""2002-10-01T00:00:00""}},{{""DoB"":""2002-10-02T00:00:00""}}],""JunkCollection"":[{{""Foo"":""junk value""}}],""NestedReference"":{{""DoB"":""2002-09-01T00:00:00""}}}}]', +'{{""Name"":""r1"",""JunkCollection"":[{{""Foo"":""junk value""}}],""JunkReference"":{{""Something"":""SomeValue"" }},""Number"":1.5,""NestedCollection"":[{{""DoB"":""2000-02-01T00:00:00"",""JunkReference"":{{""Something"":""SomeValue""}}}},{{""DoB"":""2000-02-02T00:00:00""}}],""NestedReference"":{{""DoB"":""2000-01-01T00:00:00""}}}}', +'{{""MyBool"":true,""JunkCollection"":[{{""Foo"":""junk value""}}],""Name"":""r1 ctor"",""JunkReference"":{{""Something"":""SomeValue"" }},""NestedCollection"":[{{""DoB"":""2001-02-01T00:00:00""}},{{""DoB"":""2001-02-02T00:00:00""}}],""NestedReference"":{{""JunkCollection"":[{{""Foo"":""junk value""}}],""DoB"":""2001-01-01T00:00:00""}}}}', 1)"); } @@ -140,11 +140,11 @@ N'{{""MyBool"":true,""JunkCollection"":[{{""Foo"":""junk value""}}],""Name"":""r { ctx.Database.ExecuteSqlRaw(@"INSERT INTO [Entities] ([Collection], [CollectionWithCtor], [Reference], [ReferenceWithCtor], [Id], [Name]) VALUES( -N'[{{""Name"":""e1_c1"",""ShadowDouble"":5.5}},{{""ShadowDouble"":20.5,""Name"":""e1_c2""}}]', -N'[{{""Name"":""e1_c1 ctor"",""ShadowNullableByte"":6}},{{""ShadowNullableByte"":null,""Name"":""e1_c2 ctor""}}]', -N'{{""Name"":""e1_r"", ""ShadowString"":""Foo""}}', -N'{{""ShadowInt"":143,""Name"":""e1_r ctor""}}', +'[{{""Name"":""e1_c1"",""ShadowDouble"":5.5}},{{""ShadowDouble"":20.5,""Name"":""e1_c2""}}]', +'[{{""Name"":""e1_c1 ctor"",""ShadowNullableByte"":6}},{{""ShadowNullableByte"":null,""Name"":""e1_c2 ctor""}}]', +'{{""Name"":""e1_r"", ""ShadowString"":""Foo""}}', +'{{""ShadowInt"":143,""Name"":""e1_r ctor""}}', 1, -N'e1')"); +'e1')"); } } diff --git a/test/EFCore.Jet.FunctionalTests/Query/PrimitiveCollectionsQueryJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/PrimitiveCollectionsQueryJetTest.cs index 7f13235..f5e4e1e 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/PrimitiveCollectionsQueryJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/PrimitiveCollectionsQueryJetTest.cs @@ -18,7 +18,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.Query; /// This exercises the older translation paths for e.g. Contains, to make sure things work for providers with no queryable constant/ /// parameter support. /// -public class PrimitiveCollectionsQueryJetTest : PrimitiveCollectionsQueryTestBase< +public class PrimitiveCollectionsQueryJetTest : PrimitiveCollectionsQueryRelationalTestBase< PrimitiveCollectionsQueryJetTest.PrimitiveCollectionsQueryJetFixture> { public PrimitiveCollectionsQueryJetTest(PrimitiveCollectionsQueryJetFixture fixture, ITestOutputHelper testOutputHelper) @@ -33,10 +33,10 @@ public class PrimitiveCollectionsQueryJetTest : PrimitiveCollectionsQueryTestBas await base.Inline_collection_of_ints_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Int` IN (10, 999) """); } @@ -45,10 +45,10 @@ WHERE [p].[Int] IN (10, 999) await base.Inline_collection_of_nullable_ints_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IN (10, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`NullableInt` IN (10, 999) """); } @@ -57,10 +57,10 @@ WHERE [p].[NullableInt] IN (10, 999) await base.Inline_collection_of_nullable_ints_Contains_null(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = 999 + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`NullableInt` IS NULL OR `p`.`NullableInt` = 999 """); } @@ -124,10 +124,10 @@ WHERE ( await base.Inline_collection_Contains_with_one_value(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] = 2 + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` = 2 """); } @@ -136,10 +136,10 @@ WHERE [p].[Id] = 2 await base.Inline_collection_Contains_with_two_values(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] IN (2, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` IN (2, 999) """); } @@ -148,10 +148,10 @@ WHERE [p].[Id] IN (2, 999) await base.Inline_collection_Contains_with_three_values(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] IN (2, 999, 1000) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` IN (2, 999, 1000) """); } @@ -160,13 +160,13 @@ WHERE [p].[Id] IN (2, 999, 1000) await base.Inline_collection_Contains_with_all_parameters(async); AssertSql( -""" + """ @__i_0='2' @__j_1='999' -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] IN (@__i_0, @__j_1) +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` IN (@__i_0, @__j_1) """); } @@ -175,12 +175,12 @@ WHERE [p].[Id] IN (@__i_0, @__j_1) await base.Inline_collection_Contains_with_constant_and_parameter(async); AssertSql( -""" + """ @__j_0='999' -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] IN (2, @__j_0) +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` IN (2, @__j_0) """); } @@ -189,12 +189,12 @@ WHERE [p].[Id] IN (2, @__j_0) await base.Inline_collection_Contains_with_mixed_value_types(async); AssertSql( -""" + """ @__i_0='11' -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (999, @__i_0, [p].[Id], [p].[Id] + [p].[Int]) +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Int` IN (999, @__i_0, `p`.`Id`, `p`.`Id` + `p`.`Int`) """); } @@ -203,10 +203,10 @@ WHERE [p].[Int] IN (999, @__i_0, [p].[Id], [p].[Id] + [p].[Int]) await base.Inline_collection_Contains_as_Any_with_predicate(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] IN (2, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` IN (2, 999) """); } @@ -215,10 +215,10 @@ WHERE [p].[Id] IN (2, 999) await base.Inline_collection_negated_Contains_as_All(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] NOT IN (2, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` NOT IN (2, 999) """); } @@ -232,10 +232,10 @@ WHERE [p].[Id] NOT IN (2, 999) await base.Parameter_collection_of_ints_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Int` IN (10, 999) """); } @@ -244,10 +244,10 @@ WHERE [p].[Int] IN (10, 999) await base.Parameter_collection_of_nullable_ints_Contains_int(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Int` IN (10, 999) """); } @@ -256,10 +256,10 @@ WHERE [p].[Int] IN (10, 999) await base.Parameter_collection_of_nullable_ints_Contains_nullable_int(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = 999 + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`NullableInt` IS NULL OR `p`.`NullableInt` = 999 """); } @@ -268,10 +268,10 @@ WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = 999 await base.Parameter_collection_of_strings_Contains_non_nullable_string(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] IN (N'10', N'999') + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`String` IN ('10', '999') """); } @@ -280,10 +280,10 @@ WHERE [p].[String] IN (N'10', N'999') await base.Parameter_collection_of_strings_Contains_nullable_string(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IS NULL OR [p].[NullableString] = N'999' + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`NullableString` IS NULL OR `p`.`NullableString` = '999' """); } @@ -292,10 +292,10 @@ WHERE [p].[NullableString] IS NULL OR [p].[NullableString] = N'999' await base.Parameter_collection_of_DateTimes_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[DateTime] IN ('2020-01-10T12:30:00.0000000Z', '9999-01-01T00:00:00.0000000Z') + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`DateTime` IN (#2020-01-10 12:30:00#, #9999-01-01#) """); } @@ -304,10 +304,10 @@ WHERE [p].[DateTime] IN ('2020-01-10T12:30:00.0000000Z', '9999-01-01T00:00:00.00 await base.Parameter_collection_of_bools_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Bool] = CAST(1 AS bit) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Bool` = TRUE """); } @@ -316,10 +316,10 @@ WHERE [p].[Bool] = CAST(1 AS bit) await base.Parameter_collection_of_enums_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Enum] IN (0, 3) + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Enum` IN (0, 3) """); } @@ -328,9 +328,9 @@ WHERE [p].[Enum] IN (0, 3) await base.Parameter_collection_null_Contains(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` WHERE 0 = 1 """); } @@ -479,10 +479,10 @@ WHERE ( await base.Column_collection_projection_from_top_level(async); AssertSql( -""" -SELECT [p].[Ints] -FROM [PrimitiveCollectionsEntity] AS [p] -ORDER BY [p].[Id] + """ +SELECT `p`.`Ints` +FROM `PrimitiveCollectionsEntity` AS `p` +ORDER BY `p`.`Id` """); } @@ -519,12 +519,12 @@ ORDER BY [p].[Id] await base.Column_collection_equality_parameter_collection(async); AssertSql( -""" -@__ints_0='[1,10]' (Size = 4000) + """ +@__ints_0='[1,10]' (Size = 255) -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Ints] = @__ints_0 +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Ints` = @__ints_0 """); } @@ -533,10 +533,10 @@ WHERE [p].[Ints] = @__ints_0 await base.Column_collection_equality_inline_collection(async); AssertSql( -""" -SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Ints] = N'[1,10]' + """ +SELECT `p`.`Id`, `p`.`Bool`, `p`.`Bools`, `p`.`DateTime`, `p`.`DateTimes`, `p`.`Enum`, `p`.`Enums`, `p`.`Int`, `p`.`Ints`, `p`.`NullableInt`, `p`.`NullableInts`, `p`.`NullableString`, `p`.`NullableStrings`, `p`.`String`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Ints` = '[1,10]' """); } @@ -586,10 +586,10 @@ WHERE [p].[Ints] = N'[1,10]' await base.Project_collection_of_ints_simple(async); AssertSql( -""" -SELECT [p].[Ints] -FROM [PrimitiveCollectionsEntity] AS [p] -ORDER BY [p].[Id] + """ +SELECT `p`.`Ints` +FROM `PrimitiveCollectionsEntity` AS `p` +ORDER BY `p`.`Id` """); } @@ -608,10 +608,10 @@ ORDER BY [p].[Id] // client eval AssertSql( -""" -SELECT [p].[Ints] -FROM [PrimitiveCollectionsEntity] AS [p] -ORDER BY [p].[Id] + """ +SELECT `p`.`Ints` +FROM `PrimitiveCollectionsEntity` AS `p` +ORDER BY `p`.`Id` """); } @@ -635,11 +635,11 @@ ORDER BY [p].[Id] await base.Project_primitive_collections_element(async); AssertSql( -""" -SELECT [p].[Ints], [p].[DateTimes], [p].[Strings] -FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Id] < 4 -ORDER BY [p].[Id] + """ +SELECT `p`.`Ints`, `p`.`DateTimes`, `p`.`Strings` +FROM `PrimitiveCollectionsEntity` AS `p` +WHERE `p`.`Id` < 4 +ORDER BY `p`.`Id` """); }