From 329b820e606195f2b35641bf67f38a31c1cebe74 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sat, 20 Apr 2024 11:35:31 +0200 Subject: [PATCH 1/2] Tests. --- .../Query/SqlQueryTestBase.cs | 36 +++++++++++++++++++ .../Query/SqlQuerySqlServerTest.cs | 28 +++++++++++++++ .../Query/SqlQuerySqliteTest.cs | 28 +++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/test/EFCore.Relational.Specification.Tests/Query/SqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/SqlQueryTestBase.cs index 24c7b2d23d0..8753f755ce7 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/SqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/SqlQueryTestBase.cs @@ -1221,6 +1221,42 @@ public virtual void Ad_hoc_type_with_unmapped_property_throws() () => context.Database.SqlQueryRaw(NormalizeDelimitersInRawString(@"SELECT * FROM [People]"))).Message); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task SqlQueryRaw_then_String_Length(bool async) + { + using var context = CreateContext(); + var rawQuery = NormalizeDelimitersInRawString("SELECT 'x' AS [Value] FROM [Customers]"); + var query = context.Database.SqlQueryRaw(rawQuery).Where(s => s.Length == 0); + + if (async) + { + await query.LoadAsync(); + } + else + { + query.Load(); + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task SqlQueryRaw_then_String_ToUpper_String_Length(bool async) + { + using var context = CreateContext(); + var rawQuery = NormalizeDelimitersInRawString("SELECT 'x' AS [Value] FROM [Customers]"); + var query = context.Database.SqlQueryRaw(rawQuery).Where(s => s.ToUpper().Length == 0); + + if (async) + { + await query.LoadAsync(); + } + else + { + query.Load(); + } + } + protected class Blog { public int Id { get; set; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs index 05de4ce1604..5d03c225058 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SqlQuerySqlServerTest.cs @@ -785,6 +785,34 @@ public override async Task SqlQueryRaw_composed_with_common_table_expression(boo Assert.Equal(RelationalStrings.FromSqlNonComposable, exception.Message); } + public override async Task SqlQueryRaw_then_String_Length(bool async) + { + await base.SqlQueryRaw_then_String_Length(async); + + AssertSql( + """ +SELECT [s].[Value] +FROM ( + SELECT 'x' AS "Value" FROM "Customers" +) AS [s] +WHERE CAST(LEN([s].[Value]) AS int) = 0 +"""); + } + + public override async Task SqlQueryRaw_then_String_ToUpper_String_Length(bool async) + { + await base.SqlQueryRaw_then_String_ToUpper_String_Length(async); + + AssertSql( + """ +SELECT [s].[Value] +FROM ( + SELECT 'x' AS "Value" FROM "Customers" +) AS [s] +WHERE CAST(LEN(UPPER([s].[Value])) AS int) = 0 +"""); + } + protected override DbParameter CreateDbParameter(string name, object value) => new SqlParameter { ParameterName = name, Value = value }; diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/SqlQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/SqlQuerySqliteTest.cs index 972a7bdc645..8a80cba557a 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/SqlQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/SqlQuerySqliteTest.cs @@ -79,6 +79,34 @@ public override async Task SqlQueryRaw_composed_with_common_table_expression(boo """); } + public override async Task SqlQueryRaw_then_String_Length(bool async) + { + await base.SqlQueryRaw_then_String_Length(async); + + AssertSql( + """ +SELECT "s"."Value" +FROM ( + SELECT 'x' AS "Value" FROM "Customers" +) AS "s" +WHERE length("s"."Value") = 0 +"""); + } + + public override async Task SqlQueryRaw_then_String_ToUpper_String_Length(bool async) + { + await base.SqlQueryRaw_then_String_ToUpper_String_Length(async); + + AssertSql( + """ +SELECT "s"."Value" +FROM ( + SELECT 'x' AS "Value" FROM "Customers" +) AS "s" +WHERE length(upper("s"."Value")) = 0 +"""); + } + protected override DbParameter CreateDbParameter(string name, object value) => new SqliteParameter { ParameterName = name, Value = value }; From f255fddb44e92f4d9787f4dc96118c03a0c13fad Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sat, 20 Apr 2024 11:35:47 +0200 Subject: [PATCH 2/2] Fix implementation. --- .../Query/Internal/CosmosStringMemberTranslator.cs | 4 ++-- .../Query/Internal/SqlServerStringMemberTranslator.cs | 4 ++-- .../Query/Internal/SqliteStringLengthTranslator.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs b/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs index 5d13ccf6d06..0bc92dece7f 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs @@ -37,11 +37,11 @@ public CosmosStringMemberTranslator(ISqlExpressionFactory sqlExpressionFactory) IDiagnosticsLogger logger) { if (member.Name == nameof(string.Length) - && instance?.Type == typeof(string)) + && member.DeclaringType == typeof(string)) { return _sqlExpressionFactory.Function( "LENGTH", - new[] { instance }, + new[] { instance! }, returnType); } diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerStringMemberTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerStringMemberTranslator.cs index befa6f2c79e..90dd6fc949a 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerStringMemberTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerStringMemberTranslator.cs @@ -39,12 +39,12 @@ public SqlServerStringMemberTranslator(ISqlExpressionFactory sqlExpressionFactor IDiagnosticsLogger logger) { if (member.Name == nameof(string.Length) - && instance?.Type == typeof(string)) + && member.DeclaringType == typeof(string)) { return _sqlExpressionFactory.Convert( _sqlExpressionFactory.Function( "LEN", - new[] { instance }, + new[] { instance! }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(long)), diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteStringLengthTranslator.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteStringLengthTranslator.cs index 22882bcf4e7..952f15a3f14 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteStringLengthTranslator.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteStringLengthTranslator.cs @@ -37,11 +37,11 @@ public SqliteStringLengthTranslator(ISqlExpressionFactory sqlExpressionFactory) MemberInfo member, Type returnType, IDiagnosticsLogger logger) - => instance?.Type == typeof(string) + => member.DeclaringType == typeof(string) && member.Name == nameof(string.Length) ? _sqlExpressionFactory.Function( "length", - new[] { instance }, + new[] { instance! }, nullable: true, argumentsPropagateNullability: new[] { true }, returnType)