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

Cannot pass a field with an interface type into an EF extension #35699

Open
makingbloke opened this issue Feb 27, 2025 · 2 comments
Open

Cannot pass a field with an interface type into an EF extension #35699

makingbloke opened this issue Feb 27, 2025 · 2 comments

Comments

@makingbloke
Copy link

Bug description

I have created a DBFunctions / IMethodCallTranslator extension called FreeTextSearch (The idea being that it provides a wrapper round the SQLite free text search Match method).

The prototype for the extension is in DbFunctionsExtensions.cs:

public static bool FreeTextSearch(this DbFunctions _, object propertyReference, string freeText, [NotParameterized]IFreeTextConfig config) => throw new NotImplementedException("This method is for use with Entity Framework Core only and has no in-memory implementation.");

When the extension is called like this (in Tests.cs):

IFreeTextConfig config = new SqliteFreeTextConfig(); IQueryable<TestTableDto> query = context.TestTable.Where(e => EF.Functions.FreeTextSearch(e.TextContent!, "MIKE", config));

The translator fails to get called and the an InvalidOperationException with the text shown below is raised:

System.InvalidOperationException: 'The LINQ expression 'DbSet()
.Where(t => __Functions_0
.FreeTextSearch(
propertyReference: t.TextContent,
freeText: "MIKE",
config: (IFreeTextConfig)SqliteFreeTextConfig))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'

However, when I change IFreeTextConfig to SqliteFreeTextConfig (see below) then it works fine and the translator code gets called.

SqliteFreeTextConfig config = new SqliteFreeTextConfig(); IQueryable<TestTableDto> query = context.TestTable.Where(e => EF.Functions.FreeTextSearch(e.TextContent!, "MIKE", config));

The argument config in the method FreeTextSearch is type IFreeTextConfig so why does it not work if I pass an interface but does when I pass a concrete class?

Attached is a project that can be used to demonstrate the issue.

Thanks,

Mike

EntityFrameworkTest.zip

Your code

.

Stack traces


Verbose output


EF Core version

9.0.2

Database provider

Microsoft.EntityFrameworkCore.Sqlite

Target framework

.Net 9.0

Operating system

Windows 11

IDE

Visual Studio 2022 17.13.2

@roji
Copy link
Member

roji commented Feb 28, 2025

This is likely because in the expression tree, a Convert node is introduced to cast up from SqliteFreeTextConfig to IFreeTextConfig, and that blocks usage of the IMethodTranslator (since it's a complex fragment etc). We can look into handling more Convert node scenarios, but this is a quite niche and we're very unlikely to get around to any time soon - I'm placing this in the backlog.

In the meantime, avoid using interfaces here and just pass the concrete type.

@roji roji added this to the Backlog milestone Feb 28, 2025
@makingbloke
Copy link
Author

Thanks, Now I know what the issue is I can code round it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants