首页 > 解决方案 > EF Core 3 - 在 Where 子句中使用字符串的扩展方法

问题描述

我有一个简单的字符串扩展方法:

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");
    }
  }

当我尝试在这样的Where()子句中调用此方法时:

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)
          );
      }

我有一个错误:无法翻译 LINQ 表达式...

如果我Replace()在内部使用调用,Where()它工作正常。例如:

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

但是我的代码中有几个地方需要以这种方式转换字符串,所以我想将它移到一个单独的方法中。

有没有可能让它工作?

标签: c#entity-framework-core

解决方案


这里的不同之处在于,当您在Where子句中内联方法时,编译器会生成带有多个 Replace 调用的 Expression Tree。当您调用时ReplaceAccents,编译器仅生成此调用,EF 无法访问该方法的主体。所以你需要一种扩展表达式树的方法。

有很多解决方案可以做到这一点。但是试试这个扩展,它是为此而设计的。 https://github.com/axelheer/nein-linq/

根据文档,您必须进行以下代码更改:

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");
    }
}

然后您可以在ToInjectable()通话后使用您的功能

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)
          );
      }

推荐阅读