Skip to content
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

Provider specific plugin method translator never gets called for indexer property #23410

Closed
lauxjpn opened this issue Nov 19, 2020 · 7 comments · Fixed by #23420
Closed

Provider specific plugin method translator never gets called for indexer property #23410

lauxjpn opened this issue Nov 19, 2020 · 7 comments · Fixed by #23420
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Milestone

Comments

@lauxjpn
Copy link
Contributor

lauxjpn commented Nov 19, 2020

There seems to be either a bug or a breaking change of which we are not aware of, where an indexer property (meaning a get_Item() method) is internally translated by EF Core, but is not forwarded (not even if EF Core cannot translate it itself) to method translators.

For EF Core 3.1.x, the following test would have worked (but didn't exist yet):

public class JsonNewtonsoftDomQueryTest : IClassFixture<JsonNewtonsoftDomQueryTest.JsonNewtonsoftDomQueryFixture>
{
    [Fact]
    public void Text_output_on_document_property()
    {
        using var ctx = CreateContext();
        var x = ctx.JsonEntities.Single(e => e.CustomerJObject["Name"].Value<string>() == "Joe");

        Assert.Equal("Joe", x.CustomerJToken["Name"].Value<string>());
        AssertSql(
            @"SELECT `j`.`Id`, `j`.`CustomerJObject`, `j`.`CustomerJToken`
FROM `JsonEntities` AS `j`
WHERE JSON_UNQUOTE(JSON_EXTRACT(`j`.`CustomerJObject`, '$.Name')) = 'Joe'
LIMIT 2");
    }
}

The part we are looking at here is e.CustomerJObject["Name"].Value<string>().
While this works in EF Core 3.1.x and does not in EF Core 5.0.0, the following works in both:

public class JsonNewtonsoftDomQueryTest : IClassFixture<JsonNewtonsoftDomQueryTest.JsonNewtonsoftDomQueryFixture>
{
    [Fact]
    public void Text_output_on_document_property_root()
    {
        using var ctx = CreateContext();
        var x = ctx.JsonEntities.Single(e => e.CustomerJObject.Root["Name"].Value<string>() == "Joe");

        Assert.Equal("Joe", x.CustomerJToken["Name"].Value<string>());
        AssertSql(
            @"SELECT `j`.`Id`, `j`.`CustomerJObject`, `j`.`CustomerJToken`
FROM `JsonEntities` AS `j`
WHERE JSON_UNQUOTE(JSON_EXTRACT(`j`.`CustomerJObject`, '$.Name')) = 'Joe'
LIMIT 2");
    }
}

So using a property before the indexer (e.CustomerJObject.Root["Name"].Value<string>()), leads to the query being pushed to our method translator again.

The issue here seems to be the following call that was added in EF Core 5.0:

// EF Indexer property
if (methodCallExpression.TryGetIndexerArguments(_model, out source, out propertyName))
{
return TryBindMember(Visit(source), MemberIdentity.Create(propertyName))
?? QueryCompilationContext.NotTranslatedExpression;
}

It will return null even if it cannot translate the expression, instead of calling method translators in this case as I would have expected.

This is tracked on our repo under PomeloFoundation/Pomelo.EntityFrameworkCore.MySql#1252.


EF Core version: 5.0
Database provider: Pomelo.Microsoft.EntityFrameworkCore.MySql
Target framework: .NET 5.0

@lauxjpn
Copy link
Contributor Author

lauxjpn commented Nov 19, 2020

Ah, okay it seems you guys are already working on this one, because your current code is already different from the one I am locally looking at, where QueryCompilationContext.NotTranslatedExpression does not seem to exist yet:

// EF Indexer property
if (methodCallExpression.TryGetIndexerArguments(_model, out source, out propertyName))
{
    return TryBindMember(Visit(source), MemberIdentity.Create(propertyName));
}

@smitpatel
Copy link
Contributor

Well it is regression and a bug. It should fall back to method call translators since the method can exist outside of indexer properties too.

@smitpatel
Copy link
Contributor

smitpatel commented Nov 20, 2020

@lauxjpn - I have submitted a patch for this in #23420. Can you verify that it fixes the issue you are seeing? You can pull that branch and build package out of it (using build.cmd/sh -pack) and use those packages against MySql provider to test.

@ajcvickers - I looked into adding a test for the scenario in our code

  • Unit test is not possible because there are various different service/non-service objects and also requiring a query root.
  • The only way to test would be to add a custom type with implicit mapping using typeMappingPlugin and add a custom MethodCallTranslatorPlugin (essentially what MySql has done for Json support).

@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Nov 20, 2020
@lauxjpn
Copy link
Contributor Author

lauxjpn commented Nov 22, 2020

@smitpatel Thanks for fixing! I can confirm that our tests and access to the JSON property via indexer now works as expected.
Funny, in all those years I never came across AppContext and had always implemented my own opt-out handling.

@ajcvickers
Copy link
Contributor

@smitpatel

The only way to test would be to add a custom type with implicit mapping using typeMappingPlugin and add a custom MethodCallTranslatorPlugin (essentially what MySql has done for Json support)

This seems doable. Presumably we already have tests for MethodCallTranslatorPlugins to which we can add this scenario.

@smitpatel
Copy link
Contributor

We don't have tests for plugins AFAIK. 🤔

@ajcvickers
Copy link
Contributor

Sounds like we need some then!

smitpatel added a commit that referenced this issue Nov 23, 2020
smitpatel added a commit that referenced this issue Nov 24, 2020
smitpatel added a commit that referenced this issue Nov 24, 2020
smitpatel added a commit that referenced this issue Nov 24, 2020
@ajcvickers ajcvickers changed the title [REGRESSION] Provider specific plugin method translator never gets called for indexer property Provider specific plugin method translator never gets called for indexer property Dec 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Projects
None yet
4 participants