EF Core 3 - Using an extension method of string inside Where clause

蹲街弑〆低调 提交于 2021-02-05 12:09:35

问题


I have a simple extension method for strings:

public static class FrenchStringExtensions
  {
    public static string ReplaceAccents(this string str)
    {
      return str
        .Replace("ç", "c")
        .Replace("é", "e")
        .Replace("ê", "e")
        .Replace("è", "e")
        .Replace("ë", "e")
        .Replace("â", "a")
        .Replace("à", "a")
        .Replace("î", "i")
        .Replace("ï", "i")
        .Replace("ô", "o")
        .Replace("û", "u")
        .Replace("ù", "u")
        .Replace("ü", "u");
    }
  }

When I try to call this method inside Where() clause like this:

var supportTeamsQuery = this.MasterContext.IncidentSupportTeams
        .AsNoTracking()
        .IsActive();

      if (!string.IsNullOrEmpty(pattern))
      {
        pattern = pattern.ToLower().ReplaceAccents().Trim();

        supportTeamsQuery = supportTeamsQuery
          .Where(st =>
            st.Name.ToLower().ReplaceAccents().Contains(pattern)
          );
      }

I have an error: The LINQ expression could not be translated...

If I use Replace() calls right inside Where() it works fine. For example:

supportTeamsQuery = supportTeamsQuery
          .Where(st =>
            st.Name
            .ToLower()
            .Replace("ç", "c")
            .Replace("é", "e")
            .Replace("ê", "e")
            ...
            .Contains(pattern)
          );

But I have several places in my code where I need to transform string this way so I want to move it to a separate method.

Is it possible to make it works?


回答1:


Difference here that when you inline methods in Where clause, compiler generates Expression Tree with several Replace calls. When you call ReplaceAccents, compiler generates only this call and EF can not access to body of that method. So you need a way to expand Expression Tree.

There are many solutions to do that. But try this extension, which is designed for that. https://github.com/axelheer/nein-linq/

According to the documentation, you have to do the following code changes:

public static class FrenchStringExtensions
{
    [InjectLambda]
    public static string ReplaceAccents(this string str)
    {
       _replaceAccentsFunc ??= ReplaceAccents().Compile();
       return _replaceAccentsFunc(str);
    }

    Func<string, string> _replaceAccentsFunc;

    private static Expression<Func<string, string>> ReplaceAccents()
    {
       return str =>
         .Replace("ç", "c")
         .Replace("é", "e")
         .Replace("ê", "e")
         .Replace("è", "e")
         .Replace("ë", "e")
         .Replace("â", "a")
         .Replace("à", "a")
         .Replace("î", "i")
         .Replace("ï", "i")
         .Replace("ô", "o")
         .Replace("û", "u")
         .Replace("ù", "u")
         .Replace("ü", "u");
    }
}

Then you can use your function after ToInjectable() call

var supportTeamsQuery = this.MasterContext.IncidentSupportTeams
        .ToInjectable()
        .AsNoTracking()
        .IsActive();

      if (!string.IsNullOrEmpty(pattern))
      {
        pattern = pattern.ToLower().ReplaceAccents().Trim();

        supportTeamsQuery = supportTeamsQuery
          .Where(st =>
            st.Name.ToLower().ReplaceAccents().Contains(pattern)
          );
      }


来源:https://stackoverflow.com/questions/64983665/ef-core-3-using-an-extension-method-of-string-inside-where-clause

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!