实体框架、代码优先和全文搜索

2024-01-24

我意识到人们提出了很多与全文搜索和实体框架相关的问题,但我希望这个问题有所不同。

我正在使用实体框架,代码优先,需要进行全文搜索。当我需要执行全文搜索时,我通常还会有其他条件/限制 - 例如跳过前 500 行,或过滤另一列等。

我发现这是使用表值函数处理的 - 请参阅http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx。这似乎是正确的想法。

不幸的是,直到 Entity Framework 5.0 才支持表值函数(即使如此,我相信 Code First 也不支持它们)。

我真正的问题是,对于 Entity Framework 4.3 和 Entity Framework 5.0,处理此问题的最佳方法有哪些建议。但具体来说:

  1. 除了动态 SQL(通过System.Data.Entity.DbSet.SqlQuery,例如),实体框架 4.3 是否有可用的选项?

  2. 如果我升级到实体框架 5.0,有没有办法可以先通过代码使用表值函数?

谢谢, 埃里克


使用 EF6 中引入的拦截器,您可以在 linq 中标记全文搜索,然后在 dbcommand 中替换它,如中所述http://www.entityframework.info/Home/FullTextSearch http://www.entityframework.info/Home/FullTextSearch:

public class FtsInterceptor : IDbCommandInterceptor
{
    private const string FullTextPrefix = "-FTSPREFIX-";

    public static string Fts(string search)
    {
        return string.Format("({0}{1})", FullTextPrefix, search);
    }

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

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

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

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

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

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

    public static void RewriteFullTextQuery(DbCommand cmd)
    {
        string text = cmd.CommandText;
        for (int i = 0; i < cmd.Parameters.Count; i++)
        {
            DbParameter parameter = cmd.Parameters[i];
            if (parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength))
            {
                if (parameter.Value == DBNull.Value)
                    continue;
                var value = (string)parameter.Value;
                if (value.IndexOf(FullTextPrefix) >= 0)
                {
                    parameter.Size = 4096;
                    parameter.DbType = DbType.AnsiStringFixedLength;
                    value = value.Replace(FullTextPrefix, ""); // remove prefix we added n linq query
                    value = value.Substring(1, value.Length - 2);
                    // remove %% escaping by linq translator from string.Contains to sql LIKE
                    parameter.Value = value;
                    cmd.CommandText = Regex.Replace(text,
                        string.Format(
                            @"\[(\w*)\].\[(\w*)\]\s*LIKE\s*@{0}\s?(?:ESCAPE N?'~')",
                            parameter.ParameterName),
                        string.Format(@"contains([$1].[$2], @{0})",
                                    parameter.ParameterName));
                    if (text == cmd.CommandText)
                        throw new Exception("FTS was not replaced on: " + text);
                    text = cmd.CommandText;
                }
            }
        }
    }

}
static class LanguageExtensions
{
    public static bool In<T>(this T source, params T[] list)
    {
        return (list as IList<T>).Contains(source);
    }
}

例如,如果您有带有 FTS 索引字段 NoteText 的 Note 类:

public class Note
{
    public int NoteId { get; set; }
    public string NoteText { get; set; }
}

和它的 EF 映射

public class NoteMap : EntityTypeConfiguration<Note>
{
    public NoteMap()
    {
        // Primary Key
        HasKey(t => t.NoteId);
    }
}

及其背景:

public class MyContext : DbContext
{
    static MyContext()
    {
        DbInterception.Add(new FtsInterceptor());
    }

    public MyContext(string nameOrConnectionString) : base(nameOrConnectionString)
    {
    }

    public DbSet<Note> Notes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new NoteMap());
    }
}

您可以使用非常简单的 FTS 查询语法:

class Program
{
    static void Main(string[] args)
    {
        var s = FtsInterceptor.Fts("john");

        using (var db = new MyContext("CONNSTRING"))
        {
            var q = db.Notes.Where(n => n.NoteText.Contains(s));
            var result = q.Take(10).ToList();
        }
    }
}

这将生成如下 SQL

exec sp_executesql N'SELECT TOP (10) 
[Extent1].[NoteId] AS [NoteId], 
[Extent1].[NoteText] AS [NoteText]
FROM [NS].[NOTES] AS [Extent1]
WHERE contains([Extent1].[NoteText], @p__linq__0)',N'@p__linq__0 char(4096)',@p__linq__0='(john)   

请注意,您应该使用局部变量,并且不能将 FTS 包装器移动到表达式内,例如

var q = db.Notes.Where(n => n.NoteText.Contains(FtsInterceptor.Fts("john")));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实体框架、代码优先和全文搜索 的相关文章

随机推荐

  • 如何重命名 GitHub 上的存储库?

    我想重命名 GitHub 上的一个存储库 但当出现一个大红色警告时 我感到害怕 我们不会从旧位置设置任何重定向 您将需要更新本地存储库以指向新位置 重命名可能需要几分钟才能完成 有谁有关于如何手动完成 1 和 2 的分步说明吗 或者我必须在
  • JPA Criteria API - 子类上带有字段的条件

    我有一个名为Issue和实体称为UserIssue UserIssue延伸Issue Inheritance strategy InheritanceType JOINED Entity name ISSUE public class Is
  • CMake 中的版本正则表达式

    我想验证用户指定的版本字符串 确保它由三个句点分隔的数字组成 e g 1 20 300 但我不知道如何编写这样的正则表达式 下面的代码只是一个尝试 if PROJECT VERSION MATCHES 0 9 0 9 0 9 message
  • 为什么 [[[!![]+[]]+[]]+[]][+[]][+[]] 的计算结果为 t? [复制]

    这个问题在这里已经有答案了 我发现在 JavaScript 中 评估为 t 这怎么可能 我确实知道 评估为true 但是如何从中获得 t 呢 console log None
  • mysql date_sub 使用字段作为间隔

    我需要 mysql 和 date sub 方面的帮助 我有一个表调用活动 Activity id deadline alert Activity 1 2011 04 18 1 DAY Activity 2 2011 04 13 1 MONT
  • 将 Unicode 文本放置到具有 NULL 所有者窗口的剪贴板上时出现意外行为

    我正在尝试将文本从我正在处理的 Windows 桌面应用程序中放置到剪贴板上 但我遇到了一些我不理解的行为 我正在使用的功能如下 bool Clipboard CopyText const XStringW txt size t memsi
  • 流畅地调用await而不使用括号

    有没有办法重构这条线 var result await Foo Bar 这样它就不会使用括号 也不会将等待结果分配给临时变量 我正在尝试构建一个支持长时间操作的流畅框架 当您需要将 wait 括在括号中时 现实世界的代码会变得非常丑陋 va
  • Python 3 - 从整数转换为“字节”然后连接它们(用于串行传输)

    经过多次毫无结果的搜索 我在理解 Python 3 2 中处理 字节 和十六进制内容的方式时遇到了一个非常具体的问题 我知道我误解了 但似乎无法找到正确的路径 我的最终目标是使用python串行模块来传输字节序列 有些字节是静态的 不会改变
  • 使用 ffmpeg 将视频从 .264 转换为 .265 (HEVC)

    我看到关于这个主题的一些问题 但我仍然收到错误 我想要做的就是将库中的视频转换为 HEVC 以便它们占用更少的空间 我试过这个 ffmpeg i input mp4 c v libx265 output mp4 ffmpeg 似乎需要很长时
  • iOS4进入后台播放音频

    当谈论在后台播放音频时 文档写得相当糟糕 它给人的印象是 要继续播放当前正在播放的音频 您只需将键 值对添加到info plist文件和wallah 这很神奇 然而 这种情况并非如此 例如 如果我播放 2 分钟长的 mp3 显然音频足够长
  • NSCalendar 日差错误

    我正在尝试使用 NSCalendar currentCalendar ordinalityOfUnit NSDayCalendarUnit inUnit NSEraCalendarUnit forDate date 在两个不同的日期查看它们
  • 在 Apache JMeter 中配置响应超时

    我试图检查特定 HTTP 请求的响应时间是否超过 30 秒 如果是 则将其标记为失败并停止线程 有时我可以看到响应时间接近 80 秒 没有浏览器等待服务器响应那么长时间 我发现了以下三种在 JMeter 中设置超时值的方法 但这让我很困惑
  • 每当 gem 时,schedule.rb 中的配置文件与 Rails 一起使用?

    我的 Rails 应用程序的 config 文件夹中有一个名为 config yml 的文件 我还有一个初始化程序 config initializers load config rb 其中包含以下代码 APP CONFIG YAML lo
  • 如何在 Swift 中实现 didReceiveMemoryWarning?

    每当我创建一个新的 View Controller 子类时 Xcode 都会自动添加该方法 override func didReceiveMemoryWarning super didReceiveMemoryWarning Dispos
  • 如何像在 Firefox 的 Firebug 中一样在 Chrome 中编辑 CSS?

    我一直在 Firefox 中使用 Firebug 编辑 CSS 但最近注意到 Chrome 渲染我的页面的速度要快得多 带有滚动 交互元素等 因此想切换到它 我发现 Chrome 显示了计算出的 CSS 以及堆栈中哪些属性被否决 我可以一一
  • 如何使用空间掩模限制光栅处理范围?

    我试图将 MATLAB 中的栅格处理限制为仅包含 shapefile 边界内的区域 类似于 ArcGIS Spatial Analyst 函数使用mask http resources arcgis com en help main 10
  • 在 scikit-learn 中使用 ExtraTreesClassifier 时出错

    我正在尝试在 scikit learn 中对我的数据使用 ExtraTreesClassifier 我有两个 numpy 数组 X 和 y X 的尺寸为 10000 51 y 的尺寸为 10000 为了确保它们采用 numpy 数组格式 我
  • 根据特定文本拆分 XML 节点

    请建议如何根据特定注释文本拆分 xml 节点 我尝试使用xsl 文本禁用输出转义格式以放置所需的结束和开始标记 元素 我的代码是静态的 如何制作动态代码 该代码适用于注释文本方面的任意数量的祖先 即 如果祖先计数 n 然后从n to 1如何
  • 在 Android Studio 中为 NDK 项目构建符号花费太长时间

    我正在开发一个 Android 项目 该项目使用 NDK 并绑定相当大的 Boost C 库 每次启动Android Studio时 IDE在Building Symbols阶段都会花费相当长的时间 大约1个小时 在i7四核机器上或多或少
  • 实体框架、代码优先和全文搜索

    我意识到人们提出了很多与全文搜索和实体框架相关的问题 但我希望这个问题有所不同 我正在使用实体框架 代码优先 需要进行全文搜索 当我需要执行全文搜索时 我通常还会有其他条件 限制 例如跳过前 500 行 或过滤另一列等 我发现这是使用表值函