Entity Framework Core でのフルテキスト検索 - C#

Entity Framework Coreでフルテキスト検索を実装します。

概要

SQL Serverでは、ContainsやFreetextを利用したSQLを実行して、フルテキストインデックスを利用したフリーテキスト検索が利用できます。 Entity Framework Coreでもフルテキスト検索を実行したい場合がありますが、Entity Framework Coreでは直接SQL文を実行する方法は主流ではないため、 LINQのクエリ構文やメソッド構文でフリーテキスト検索を実行したいです。
この記事では、Entity Framework Coreでフルテキスト検索するコードを紹介します。

書式

Microsoft.EntityFrameworkCore.EF クラスの Functions.Contains() メソッド、Functions.FreeText() メソッドを利用します。

Contains

where Microsoft.EntityFrameworkCore.EF.Functions.Contains([検索対象列], [検索クエリ])
.Where(e => EF.Functions.Contains([検索対象列], [検索クエリ])

FreeText

where Microsoft.EntityFrameworkCore.EF.Functions.FreeText([検索対象列], [検索クエリ])
.Where(e => EF.Functions.FreeText([検索対象列], [検索クエリ])

テーブルの準備

以下のテーブルを準備します。
Working テーブル
idnamevaluecategorymemo
1Penguin300B南国にすむペンギンです
2Whale420M北極海のクジラです
3Moffu880NULLよくわからない生き物です
4Camel220M砂漠にすむラクダです
5Owl90B関東のフクロウです
6Duck120Bそこらへんのアヒルです
7Lizard60Rひっそりと生きるトカゲです

DbContextの作成

Scaffold-DbContextコマンドを使用して、Entity Framework CoreのDbContextを作成します。
手順の詳細はこちらの記事を参照してください。

プログラム

UI

下図のフォームを作成します。1行のテキストボックスを1つ、複数行(Multilineプロパティ=true)のテキストボックスを1つ、ボタンを2つ配置します。


コード

以下のコードを記述します。
using EntityFrameworkCoreFullTextIndex.models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.EntityFrameworkCore;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace EntityFrameworkCoreFullTextIndex
{
  public partial class FormContains : Form
  {
    public FormContains()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      string my_query = textBox1.Text;

      IPentecSandBoxContext ctx = new IPentecSandBoxContext();

      //List<Working> result = ctx.Workings.Where(e => EF.Functions.Contains(e.Memo, my_query)).ToList();
      List<Working> result = (from tbl in ctx.Workings where Microsoft.EntityFrameworkCore.EF.Functions.Contains(tbl.Memo, my_query) select tbl).ToList();

      foreach (Working w in result) {
        textBox2.Text += string.Format("{0:d} : {1} - {2:g} - {3}\r\n", w.Id, w.Name.Trim(), w.Value, w.Memo.Trim());
      }

    }

    private void button2_Click(object sender, EventArgs e)
    {
      string my_query = textBox1.Text;

      IPentecSandBoxContext ctx = new IPentecSandBoxContext();

      //List<Working> result = ctx.Workings.Where(e => EF.Functions.FreeText(e.Memo, my_query)).ToList();
      List<Working> result = (from tbl in ctx.Workings where Microsoft.EntityFrameworkCore.EF.Functions.FreeText(tbl.Memo, my_query) select tbl).ToList();

      foreach (Working w in result) {
        textBox2.Text += string.Format("{0:d} : {1} - {2:g} - {3}\r\n", w.Id, w.Name.Trim(), w.Value, w.Memo.Trim());
      }
    }
  }
}

解説

メソッド構文で、フルテキストインデックスの Contains 検索をする場合の記述です。今回の例では、検索時にToList()メソッドを呼び出し、リスト形式で レコードの一覧を取得しています。
List<Working> result = ctx.Workings.Where(e => EF.Functions.Contains(e.Memo, my_query)).ToList();

クエリ構文で、フルテキストインデックスの Contains 検索をする場合の記述です。今回の例では、検索時にToList()メソッドを呼び出し、リスト形式で レコードの一覧を取得しています。
List<Working> result = (from tbl in ctx.Workings where Microsoft.EntityFrameworkCore.EF.Functions.Contains(tbl.Memo, my_query) select tbl).ToList();

メソッド構文で、フルテキストインデックスの FreeText 検索をする場合の記述です。今回の例では、検索時にToList()メソッドを呼び出し、リスト形式で レコードの一覧を取得しています。
List<Working> result = ctx.Workings.Where(e => EF.Functions.FreeText(e.Memo, my_query)).ToList();

クエリ構文で、フルテキストインデックスの FreeText 検索をする場合の記述です。今回の例では、検索時にToList()メソッドを呼び出し、リスト形式で レコードの一覧を取得しています。
List<Working> result = (from tbl in ctx.Workings where Microsoft.EntityFrameworkCore.EF.Functions.FreeText(tbl.Memo, my_query) select tbl).ToList();

実行結果

プロジェクトを実行します。
ウィンドウが表示されますので、上部のテキストボックスに検索ワードを入力します。


[button1]をクリックします。Memoフィールドを検索して検索ワードが含まれる項目を表示します。


別の検索ワードでも試してみます。


該当する項目が複数ある場合は、複数件表示されます。


[button2]をクリックして、FreeTextでの検索結果です。こちらも動作しています。

補足: 複数語句、検索語句を空で実行した場合の動作

空文字列で実行した場合

検索文字列を空にして[button1]または[button2]をクリックします。
以下の例外が発生します。


エラーメッセージ
Microsoft.Data.SqlClient.SqlException
  HResult=0x80131904
  Message=フルテキスト述語が NULL または空です。
  Source=Core Microsoft SqlClient Data Provider
  スタック トレース:
  ......

複数語句で実行した場合

検索文字列を "海 クジラ" を設定して[button1]をクリックします。
以下の例外が発生します。


エラーメッセージ
Microsoft.Data.SqlClient.SqlException
  HResult=0x80131904
  Message=フルテキスト検索条件 '海 クジラ' の 'クジラ' 付近で構文エラーが発生しました。
  Source=Core Microsoft SqlClient Data Provider
  スタック トレース:
  ......

なお、[button2]の場合は、検索結果が表示できます。


検索文字列は、CONTAINS, FREETEXT句にそのまま渡されるため、CONTAINS句での検索をする場合には、"AND" や "OR" 演算子を追加する必要があります。 検索文字列を、"海 AND クジラ" に設定して、[button1]をクリックすると、検索結果のレコードが取得できます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2023-06-27
作成日: 2023-06-26
iPentec all rights reserverd.