-
Notifications
You must be signed in to change notification settings - Fork 227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add translation of string.Join overload used with List<string> parameter, fix #3105 #3106
Add translation of string.Join overload used with List<string> parameter, fix #3105 #3106
Conversation
While this fixes the |
Regarding the side effects, an interesting case might be: When changing the query from #3105 like this var q = ctx.Blogs.Select(b => new
{
b.Name,
q = b.TagsList,
w = b.TagsArray,
ListTagsJoined = string.Join(", ", b.TagsList), // the translation of this seems wrong
ArrayTagsJoined = string.Join(", ", b.TagsArray),
b.RatingsList,
b.RatingsArray,
- ListRatingsJoined = string.Join(", ", b.RatingsList),
+ ListRatingsJoined = string.Join(", ", b.RatingsList.Select(x => x == 1 ? "Bad" : x == 2 ? "Quite Bad" : "Okayish or Better")),
ArrayRatingsJoined = string.Join(", ", b.RatingsArray),
}); the translation works in SELECT b."Name", b."TagsList", b."TagsArray", array_to_string(b."TagsArray", ', ', ''), b."RatingsList", b."RatingsArray", b."Id", CASE
WHEN r.value = 1 THEN 'Bad'
WHEN r.value = 2 THEN 'Quite Bad'
ELSE 'Okayish or Better'
END, r.ordinality, array_to_string(b."RatingsArray", ', ', '')
FROM "Blogs" AS b
LEFT JOIN LATERAL unnest(b."RatingsList") WITH ORDINALITY AS r(value) ON TRUE
ORDER BY b."Id" The |
That's probably something we don't want: array_to_string() (the PG function we translate to) requires a PG array, and there can be IEnumerables which aren't that (in fact, there can technically even be .NET arrays which aren't mapped to PG arrays - though that's more rare/edge-casey). So prevent this unwanted translation, it's enough to make sure that the type mapping on the array/enumerable SqlExpression argument is an NpgsqlArrayTypeMapping - can you please add that?
Makes sense - the fact that it client-evals (no array_to_string in the actual SQL) indeed means that it's not translated, which is a good thing (since that complex LINQ expression does not represent a PG array) - there's most likely an earlier translation failure that doesn't even go into the method translator. However, it's still safer to add an explicit check here as I've suggested above - makes sense? |
{ | ||
await base.String_Join_with_array_parameter(async); | ||
await base.String_Join_with_array_of_int_parameter(async); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually seems mis-named (before your PR) - the array of int is a column, not a parameter. Can you please rename to String_Join_with_array_of_int_column
(also the string variant)? Also,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if something after your
Also,
was cut off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, nothing important.
[MemberData(nameof(IsAsyncData))] | ||
public async Task String_Join_with_array_of_string_parameter(bool async) | ||
{ | ||
// This is not in ArrayQueryTest because string.Join uses another overload for string[] than for List<string> and thus |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Sorry for the delay, I think I'll be able to look into the |
Adding the
I didn't yet manage to construct a query where something non-ArrayTypeMapped would be passed to the string.Join translator and the translation also doesn't fail even without the check. Adding a test like this probably doesn't make sense then, because it doesn't actually test what it is designed to test. public class ArrayListQueryTest : ArrayQueryTest<ArrayListQueryTest.ArrayListQueryFixture>
// ...
// This test doesn't include a List<T> as the name of this class suggests.
// The overload of string.Join that is used with a List<string> argument is declared with IEnumerable<string>.
// While we want to translate that if the argument is a List<string> or similar, we can't translate
// it for arbitrary IEnumerable<string>s. We thus need to ensure that the translation fails in
// such cases.
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public async Task String_Join_disallow_enumerable_of_string_parameter(bool async)
{
await AssertTranslationFailed(() => AssertQuery(
async,
ss => ss.Set<ArrayEntity>()
.Where(e => string.Join(", ", e.IntArray.Select(x => x.ToString())) == "3, 4"));
} Any suggestions what to put there? Or just leave it as is and add no test? Edit: When executing this test, actually something non-ArrayTypeMapped is passed to the string.Join translator. |
You may be able to reproduce a failure by doing string.Join over a value-converted Otherwise, I think it's not critical if you can't put together a test for it - it's more of safety/correctness thing at this point (even though it may become more important in the future). |
In any case, let me know when this is ready for a new review (the Github UI allows asking for another review in the Reviewers section). |
Thanks, works! Without the check, I get Is there a better way? Any preference how to proceed? |
There's some recent infra in EF for doing "ad-hoc" tests, where the test defines the model inside it - that would be ideal here, but is a bigger change. So barring that, yeah, ideally adding a value-converted array/List to ArrayQueryTest would be the way to go - it could be useful for other tests as well. It shouldn't be too hard - the main thing would be to add the new column to all the existing baselines, which can be easily done via bulk updating of the baseilnes (link, by setting the EF_TEST_REWRITE_BASELINES env var to 1 and running the tests... |
Ah, that's a really handy thing I didn't know about. I think this is ready now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last comment, otherwise LGTM.
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlStringMethodTranslator.cs
Outdated
Show resolved
Hide resolved
…sql#3105) string.Join translations are just valid if their parameter's TypeMapping is NpgsqlArrayTypeMapping.
52fee42
to
edd1eff
Compare
After they changed due to 909f589
edd1eff
to
a700ef9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quality work and responsive back-and-forths on this!
Backported to 8.0.3 via f280bb7 |
Thanks for the quick turnarounds and on-point feedback 👍 |
Not sure if I got everything right about this, but I hope it fixes #3105 :)