【问题标题】:Using Contains to search in SQLite in non-English text returns more results than expected使用 Contains 在 SQLite 中搜索非英文文本会返回比预期更多的结果
【发布时间】:2017-10-05 02:55:37
【问题描述】:

我在 WPF 应用程序中使用 Sqlite+EF,当我在数据库中搜索包含非英文字母的文本时,我得到了我期望的行 + 另一行不知道为什么会出现。 我的做法是:
dbContext.MyTable.Where(w => w.Name.Contains(someNonEnglishTextHere))

  • DB 是 Sqlite3
  • 编码为 UTF-8
  • MyTable 中的列Name 具有Collate 作为NOCASE
  • 我正在使用 EF6

当询问由 EF 形成的 sql 查询时,Contains 替换为 CHARINDEX 而不是 LIKE,有什么办法可以强制 EF 使用 LIKE 吗?如果我能做到,也许这就是解决方案。

【问题讨论】:

  • 你解决了吗?我对西里尔语有同样的问题...
  • 从来没有解决过,在内存中搜索,这样我就可以摆脱在数据库中的搜索了。

标签: c# wpf sqlite entity-framework-6


【解决方案1】:

您可以通过注入 db 拦截器来替换 CHARINDEX 函数。 将拦截器添加到 dbcontext。

class MyDBContext: DbContext
{
    static MyDBContext()
    {
        DbInterception.Add(new SqliteInterceptor());
    }
}

像这样完成你的拦截器:

class SqliteInterceptor : IDbCommandInterceptor
{
    private static Regex replaceRegex = new Regex(@"\(CHARINDEX\((.*?),\s?(.*?)\)\)\s*?>\s*?0");

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        ReplaceCharIndexFunc(command);
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        ReplaceCharIndexFunc(command);
    }

    private void ReplaceCharIndexFunc(DbCommand command)
    {
        bool isMatch = false;
        var text = replaceRegex.Replace(command.CommandText, (match) =>
        {
            if (match.Success)
            {
                string paramsKey = match.Groups[1].Value;
                string paramsColumnName = match.Groups[2].Value;
                //replaceParams
                foreach (DbParameter param in command.Parameters)
                {
                    if (param.ParameterName == paramsKey.Substring(1))
                    {
                        param.Value = string.Format("%{0}%", param.Value);
                        break;
                    }
                }
                isMatch = true;
                return string.Format("{0} LIKE {1}", paramsColumnName, paramsKey);
            }
            else
                return match.Value;
        });
        if (isMatch)
            command.CommandText = text;
    }
}

【讨论】:

    【解决方案2】:

    我已经通过重写函数解决了我的问题

     [SQLiteFunction(Arguments = 1, FuncType = FunctionType.Scalar, Name = "Lower")]
        class CustomLower : SQLiteFunction
        {
            public override object Invoke(object[] args)//characters for the growth of
            {
                return args[0].ToString().ToLower();
            }
        }
    
        [SQLiteFunction(Arguments = 2, FuncType = FunctionType.Scalar, Name = "CHARINDEX")]
        class CustomCharIndex : SQLiteFunction
        {
            public override object Invoke(object[] args)//characters for the growth of
            {
                return args[1].ToString().IndexOf(args[0].ToString(), StringComparison.Ordinal) + 1;
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-04
      • 2021-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 2020-05-20
      • 2019-09-03
      相关资源
      最近更新 更多