diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosMemberTranslatorProvider.cs b/src/EFCore.Cosmos/Query/Internal/CosmosMemberTranslatorProvider.cs index 44096c90315..6f96d25af9a 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosMemberTranslatorProvider.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosMemberTranslatorProvider.cs @@ -32,12 +32,12 @@ public CosmosMemberTranslatorProvider( IEnumerable plugins) { _plugins.AddRange(plugins.SelectMany(p => p.Translators)); - //_translators - // .AddRange( - // new[] - // { - // new NullableMemberTranslator(sqlExpressionFactory), - // }); + _translators + .AddRange( + new[] + { + new CosmosStringMemberTranslator(sqlExpressionFactory), + }); } /// diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs b/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs new file mode 100644 index 00000000000..4ec517e87d8 --- /dev/null +++ b/src/EFCore.Cosmos/Query/Internal/CosmosStringMemberTranslator.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Utilities; + +namespace Microsoft.EntityFrameworkCore.Cosmos.Query.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 CosmosStringMemberTranslator : IMemberTranslator + { + private readonly ISqlExpressionFactory _sqlExpressionFactory; + + /// + /// 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 CosmosStringMemberTranslator(ISqlExpressionFactory sqlExpressionFactory) + { + _sqlExpressionFactory = sqlExpressionFactory; + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual SqlExpression? Translate( + SqlExpression? instance, + MemberInfo member, + Type returnType, + IDiagnosticsLogger logger) + { + Check.NotNull(member, nameof(member)); + Check.NotNull(returnType, nameof(returnType)); + Check.NotNull(logger, nameof(logger)); + + if (member.Name == nameof(string.Length) + && instance?.Type == typeof(string)) + { + return _sqlExpressionFactory.Function( + "LENGTH", + new[] { instance }, + returnType); + } + + return null; + } + } +} diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index f5def3009fc..b515ca316cb 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -232,7 +232,7 @@ public override async Task Select_anonymous_constant_in_expression(bool async) await base.Select_anonymous_constant_in_expression(async); AssertSql( - @"SELECT c[""CustomerID""] + @"SELECT VALUE {""CustomerID"" : c[""CustomerID""], ""Expression"" : (LENGTH(c[""CustomerID""]) + 5)} FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } @@ -535,7 +535,7 @@ public override async Task Select_non_matching_value_types_from_length_introduce await base.Select_non_matching_value_types_from_length_introduces_explicit_cast(async); AssertSql( - @"SELECT c[""CustomerID""] + @"SELECT LENGTH(c[""CustomerID""]) AS c FROM root c WHERE ((c[""Discriminator""] = ""Order"") AND (c[""CustomerID""] = ""ALFKI"")) ORDER BY c[""OrderID""]"); diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs index 28da5e2a412..d437b3d57ed 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs @@ -983,7 +983,7 @@ FROM root c WHERE ((c[""Discriminator""] = ""Employee"") AND (c[""ReportsTo""] = null))"); } - [ConditionalTheory(Skip = "Issue #17246")] + [ConditionalTheory] public override async Task Where_string_length(bool async) { await base.Where_string_length(async); @@ -991,7 +991,7 @@ public override async Task Where_string_length(bool async) AssertSql( @"SELECT c FROM root c -WHERE (c[""Discriminator""] = ""Customer"")"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (LENGTH(c[""City""]) = 6))"); } [ConditionalTheory(Skip = "Issue #17246")]