PomeloFoundation / Pomelo.EntityFrameworkCore.MySql

Entity Framework Core provider for MySQL and MariaDB built on top of MySqlConnector
MIT License
2.69k stars 381 forks source link

string.Remove not work. #1283

Closed Flithor closed 3 years ago

Flithor commented 3 years ago

I saw the https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/clr-method-to-canonical-function-mapping said that Remove can be translate. But it not work on this library.

DbContext.Set<Entity>().Where(entity => entity.StringProp.Remove(2) == "ab");

Got

InvalidOperationException: The LINQ expression 'DbSet<Entity>
    .Where(entity => entity.StringProp.Remove(2) == "ab")' 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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

version: the last

lauxjpn commented 3 years ago

I saw the https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/clr-method-to-canonical-function-mapping said that Remove can be translate.

That is an old article about Entity Framework 6, not Entity Framework Core. When you open the article CLR Method to Canonical Function Mapping and then navigate to the grandparent article ADO.NET Entity Framework, there is no navigation back to the original article you linked. Instead, it only displays the following:

The docs.microsoft.com/ef/ site is now the main location for the Entity Framework content.

The content for this topic is now available on the following page: [Introducing Entity Framework}(https://docs.microsoft.com/en-us/ef/ef6/get-started).

EF Core introduced a provider specific function mapping page for each Microsoft provider in their docs for EF Core 5 (e.g. Function Mappings of the Microsoft SQL Server Provider). As you can see, the String.Remove() method is not even being translated by SQL Server in EF Core (and also not by SQLite) and Pomelo does not currently translate it as well.

However, in the original article you referenced, there is the EF6 translation being mentioned, which should be easy to accomplish with the string methods/functions that are supported by Pomelo:

System.String method (instance) Canonical function Notes
System.String Remove(Int32 startIndex) Substring(this, 1, startIndex)
System.String Remove(Int32 startIndex, Int32 count) Concat(Substring(this, 1, startIndex) , Substring(this, startIndex + count +1, Length(this) - (startIndex + count))) Remove(startIndex, count) is only supported if count is an integer greater than or equal to 0.

If you look at the .NET 5 source code for String.Remove(int startIndex), you get the following code, which also uses Substring() in the same way that the EF6 translation does:

// a remove that just takes a startindex.
public string Remove(int startIndex)
{
    if (startIndex < 0)
        throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);

    if (startIndex >= Length)
        throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndexLessThanLength);

    return Substring(0, startIndex);
}

Therefore, for the String.Remove(Int32 startIndex) method translation, which is the one you are interested in in your OP, you can just use the following call as a substitude:

context.MyEntities.Where(e => e.StringProp.Substring(0, 2) == "ab");
lauxjpn commented 3 years ago

@Flithor We did add official support for String.Remove() with #1284.