Entity Framework Core でフルテキスト検索を実行すると 「Microsoft.Data.SqlClient.SqlException: 引数の型 "ntext" は、"CONTAINS" の引数 2 には無効です。」 例外が発生し動作しない - C#

Entity Framework Core でフルテキスト検索を実行すると、つぎの例外が発生し動作しない現象と対処法を紹介します。
  • 「Microsoft.Data.SqlClient.SqlException: 引数の型 "ntext" は、"CONTAINS" の引数 2 には無効です。」
  • 「Microsoft.Data.SqlClient.SqlException: 引数の型 "ntext" は、"FREETEXT" の引数 2 には無効です。」

現象の確認

テーブル

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

プログラム

プロジェクトを作成し、Scaffold-DbContextコマンドを使用して、Entity Framework CoreのDbContextを作成します。
作成後以下のプログラムを作成します。

UI

下図のフォームを作成します。

コード

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 = (from tbl in ctx.Workings where Microsoft.EntityFrameworkCore.EF.Functions.Contains(tbl.Memo, my_query) select tbl).ToList();

      /*     
      //メソッド構文
      List<Working> result = ctx.Workings.Where(e => EF.Functions.Contains(e.Memo, my_query)).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 = (from tbl in ctx.Workings where Microsoft.EntityFrameworkCore.EF.Functions.FreeText(tbl.Memo, my_query) select tbl).ToList();
      
      /*     
      //メソッド構文
      List<Working> result = ctx.Workings.Where(e => EF.Functions.FreeText(e.Memo, my_query)).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());
      }
    }

  }
}

プロジェクトを実行して、[button1]または[button2]をクリックすると以下の例外が発生します。


[button1]をクリックしContains関数を実行した場合の例外は以下となります。

エラーメッセージ
Microsoft.Data.SqlClient.SqlException
  HResult=0x80131904
  Message=引数の型 "ntext" は、"CONTAINS" の引数 2 には無効です。
  Source=Core Microsoft SqlClient Data Provider
  スタック トレース:
   ...

[button2]をクリックし、FreeText関数を実行した場合は以下の例外が発生します。

エラーメッセージ
Microsoft.Data.SqlClient.SqlException
  HResult=0x80131904
  Message=引数の型 "ntext" は、"FREETEXT" の引数 2 には無効です。
  Source=Core Microsoft SqlClient Data Provider
  スタック トレース:
   ...

原因

Entity Framework Coreでtextntext型の列でフルテキスト検索を実行していることが原因と考えられます。

対処法

フルテキスト検索対象の列を text,ntext型から、varchar(MAX), nvarchar(MAX) に変更します。

テーブルデザイナで列の肩を確認すると、ntext型で定義されています。


列の型をnvarchar(MAX) に変更します。


テーブルのデータ型を変更後に再度、Scaffold-DbContextコマンドを使用してDbContextを更新します。

実行結果

プロジェクトを実行します。ウィンドウが表示されますので、上部のテキストボックスに検索ワードを入力し、[button1]または、[button2]をクリックします。
検索結果が下部のテキストボックスに表示され、フルテキスト検索が実行できたことが確認できます。

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