none
BindingSource.Filterプロパティについて RRS feed

  • 質問

  • FrameWork4.0において、DataBindingSourceのfilterプロパティに長めの文字列をセットしたところ、System.StackOverflowExceptionが発生してしまいました。

    具体的には filter = "伝票番号 = XXXXX" or  を1600回程繰り返した文字列です。

    filterプロパティについて、調べてみたのですが、限界とする件数などの記述がなかったため困っています。

    どなたかご存知でしたら教えていただけますでしょうか。

    よろしくお願いいたします。

    2015年12月21日 7:35

回答

  • こんにちは。

    試してみたところ再現しました。
    以下を参考にIN句に変更したところ発生しなくなりました。

    http://stackoverflow.com/questions/7240292/bindingsource-filter-maximum-length

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim hoge As New StringBuilder()
        'For i As Integer = 0 To 1800
        '    If hoge.Length <> 0 Then
        '        hoge.Append(" OR ")
        '    End If
        '    hoge.Append(String.Format(" test = {0} ", i))
        'Next
        For i As Integer = 0 To 1800
            If hoge.Length = 0 Then
                hoge.Append(" test in ( ")
            Else
                hoge.Append(" , ")
            End If
            hoge.Append(i)
        Next
        hoge.Append(" ) ")
        BindingSource1.Filter = hoge.ToString()
    End Sub
    
    たしかに、見当たらないですね。探し中です。

    • 回答としてマーク KBN.Y 2015年12月25日 5:26
    2015年12月21日 8:00
    モデレータ
  • BindingSource::Filter自体は、BindingSource::DataSourceが持つFilterに対して渡しているだけなので直接的な原因ではありません。

    たとえばDataView(DataTableをBindingSource::DataSourceにしたときに暗黙にソースとして扱われるオブジェクト)のRowFilterプロパティ(BindingSource::Filterはこのプロパティに設定されます)は、解析に再帰を使っているらしく、長ったらしいクエリを設定するとStackOverflowExceptionになります。

    クエリを見直すとか、Filterを使わないとか、そういう方向での回避策を考える必要がありますね。

    • 回答としてマーク KBN.Y 2015年12月25日 5:26
    2015年12月21日 8:19
  • 他の方も書かれているようですが、通常は伝票番号を1600個も個別に指定してFilterするようなことはまずありません。どのようなことをされたいのかを説明されると、きっと他に良いやり方があるように思います。
    ちなみにもしExists句が使えるのであれば、IN句よりパフォーマンスが良くなる可能性があります。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク KBN.Y 2015年12月25日 5:31
    2015年12月21日 14:47
    モデレータ

すべての返信

  • こんにちは。

    試してみたところ再現しました。
    以下を参考にIN句に変更したところ発生しなくなりました。

    http://stackoverflow.com/questions/7240292/bindingsource-filter-maximum-length

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim hoge As New StringBuilder()
        'For i As Integer = 0 To 1800
        '    If hoge.Length <> 0 Then
        '        hoge.Append(" OR ")
        '    End If
        '    hoge.Append(String.Format(" test = {0} ", i))
        'Next
        For i As Integer = 0 To 1800
            If hoge.Length = 0 Then
                hoge.Append(" test in ( ")
            Else
                hoge.Append(" , ")
            End If
            hoge.Append(i)
        Next
        hoge.Append(" ) ")
        BindingSource1.Filter = hoge.ToString()
    End Sub
    
    たしかに、見当たらないですね。探し中です。

    • 回答としてマーク KBN.Y 2015年12月25日 5:26
    2015年12月21日 8:00
    モデレータ
  • BindingSource::Filter自体は、BindingSource::DataSourceが持つFilterに対して渡しているだけなので直接的な原因ではありません。

    たとえばDataView(DataTableをBindingSource::DataSourceにしたときに暗黙にソースとして扱われるオブジェクト)のRowFilterプロパティ(BindingSource::Filterはこのプロパティに設定されます)は、解析に再帰を使っているらしく、長ったらしいクエリを設定するとStackOverflowExceptionになります。

    クエリを見直すとか、Filterを使わないとか、そういう方向での回避策を考える必要がありますね。

    • 回答としてマーク KBN.Y 2015年12月25日 5:26
    2015年12月21日 8:19
  • KBN.Y さま よろしく。

    恐らく、何かの処理をしながら抽出を積み重ねているのでは?と思います。

    いっその事、その処理中に、別の指標(boolean 型で True/False)を付けるか、別テーブルに一意コードを切り出すか、
    の方が集合で扱えるので宜しいのではないでしょうか?。
    抽象的なコメントで申し訳ないのですが。
    メンテナンスもデバッグもきっと楽になりますよ。

    • 編集済み ShiroYuki_Mot 2015年12月21日 13:59 お名前誤字訂正 失礼しました
    2015年12月21日 13:57
  • 他の方も書かれているようですが、通常は伝票番号を1600個も個別に指定してFilterするようなことはまずありません。どのようなことをされたいのかを説明されると、きっと他に良いやり方があるように思います。
    ちなみにもしExists句が使えるのであれば、IN句よりパフォーマンスが良くなる可能性があります。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク KBN.Y 2015年12月25日 5:31
    2015年12月21日 14:47
    モデレータ
  • ちなみにもしExists句が使えるのであれば、IN句よりパフォーマンスが良くなる可能性があります。

    Exists句も使えるのですね知りませんでした。
    そしてExistsで早くなるのはインデックスが絡んだ話かと思ってましたが、今回のケースでもパフォーマンスがよくなるのですね。
    今度試してみます。

    2015年12月21日 15:49
    モデレータ
  • フォーラム オペレーターの星 睦美です。KBN.Y さん、投稿ありがとうございます。

    フォーラムのユーザーからの返信があります。内容を確認いただいて更に詳しく知りたい点がありましたら返信いただければと思います。回答の励みになりますので参考になった回答には投稿者からの[回答としてマーク] をお願いします。
    ・フォーラムのヘルプ


    フォーラム オペレーター 星 睦美 - MSDN Community Support

    2015年12月22日 1:15
  • そしてExistsで早くなるのはインデックスが絡んだ話かと思ってましたが、今回のケースでもパフォーマンスがよくなるのですね。


    念のために書いておきますね。
    Existsが必ずINよりも速くなるとは限りません。どちらもインデックスが使えるときは使われますので、インデックスが必ず絡むわけでもありません。ExistsとINの違いについての記述は多くのページで見つかりますので私が詳しくここで書く必要はありませんが、いずれにしてもオプティマイザーの動作や実行プランも見ながら最終的には判断することになると思います。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2015年12月22日 2:18
    モデレータ
  • Existsが必ずINよりも速くなるとは限りません。どちらもインデックスが使えるときは使われますので

    RDBMSにおけるExists句とIN句のパフォーマンスに関する記事はたくさん見かけますが、
    私が言いたかったのは、今回のBindingSource.Filterに関しても同様なのですね、という意味でした。

    2015年12月22日 2:38
    モデレータ
  • 検証までして頂き、ありがとうございます。

    IN句とは盲点でした。

    大変参考になりました。ありがとうございます。

    2015年12月25日 5:22
  • 式の見た目上、プロパティに値を渡しているだけに見えるので、プロパティを設定した後の動作が想像しにくいですね。

    教えて頂いたように、解析に再帰を使っているとするとOverflowは納得出来ます。

    大変勉強になりました。ありがとうございます。

    2015年12月25日 5:24
  • 1600個もWHERE句に含む事が現実的でないということは理解しております。

    DatagridViewにDatasourceを新たにセットした方が楽なのですが、今回はDataGridviewにチェックボックスの列を設けていて、Datarouceを再セットしてしまうと、チェックボックスの選択状態がリセットされてしまうため、色々と書き直すのが億劫で、filterを使用してしまいました。

    コレクション系のクラスで選択状況を保存しておけば良いのですが。。。

    しかし、今回の現象から色々と知ることができました。ありがとうございました。

    2015年12月25日 5:31