none
SqlDataSourceのパラメータとしてCheckBoxを使いたい RRS feed

  • 質問

  • GridViewのDataSourceとして、SqlDataSourceを使っております。
    SQL文中に"@price"のSelectParameterがあり、CheckBoxのチェック有無により、@priceの金額をパラメータとして設定したい状況です。

    このとき、通常のControlParameterとしてaspxファイル中に設定することはできませんでした。(CheckBoxにValueがないので)
    そこで以下のようなコードを考えました。

    SqlDataSource1.SelectParameters("price").DefaultValue = IIf(CheckBox1.Checked,"0","1000")

    これをGridView1_DataBoundに記述したところ、ページを開いた時点で NullReferenceException となってしまいました。
    SqlDataSource1_Selectingに記述しても同じです。

    Button1を配置し、Button1_Clickに記述したところ、ページは開くようになりましたが、Button1をクリックした時点で
    Must declare the scalar variable "@price" とアプリケーションエラーが発生してしましました。

    この状況を打開したく、お力をいただければ幸いです。


    2020年6月29日 7:33

回答

  • 自分ならこうするという案を勝手に書いておきます。

    > 問題を再現できる必要最低限に絞ったコードをアップしてください。

    上記の依頼に反応がなく、質問者さんのやりたいことの詳細は不明ですので、質問者さんの意向には沿わないかもしれませんが。

    where 句に設定するのが金額なので、表題の「SqlDataSourceのパラメータとしてCheckBoxを使いたい」は無理です。

    どうしてもということなら、ストアドプロシージャを作ってそれに ture / false を渡し、ストアドプロシージャの中で ture / false を金額に変換して where 句に設定するということが思いつきますが、そこまでやる気は多分ないだろうと思います。

    なので、ASP.NET のコードビハインドでチェックの有無を金額に変換して where 句のパラメータに代入するのがよさそうです。それはたぶん質問者さんもそう考えたのだろうと思います。

    > SqlDataSource1_Selectingに記述しても同じです。

    とのことですので、もう一歩のところだったのかもしれませんね。

    以下のサンプルコードは、Microsoft の Northwind サンプルデータベースの Products テーブルを使って、CheckBox にチェックが入っている場合は UnitPrice が $40 以上の商品を選択するものです。

    詳しい説明はしませんが、不明点があれば質問してください。ただし、この方向で OK であればです。NG ならどこがやりたいことと違うのか、質問者さんのコードをアップするなどして詳しく説明してください。


    aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data.SqlClient;
    
    namespace WebApplication1
    {
        public partial class WebForm7 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
            {
                GridView1.DataBind();
            }
    
            protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
            {
                var command = (SqlCommand)e.Command;
                if (CheckBox1.Checked)
                {
                    command.Parameters["@UnitPrice"].Value = 40m;
                }
                else
                {
                    command.Parameters["@UnitPrice"].Value = 0m;
                }
            }
        }
    }

    .aspx

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" 
        AutoEventWireup="true" CodeBehind="WebForm7.aspx.cs" 
        Inherits="WebApplication1.WebForm7" %>
    
    <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
    </asp:Content>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
        <p>チェックを入れて Button クリックで Unit Price $40 以上の商品を選択</p>
        <asp:CheckBox ID="CheckBox1" runat="server" 
            OnCheckedChanged="CheckBox1_CheckedChanged" />    
        <asp:Button ID="Button1" runat="server" Text="Button" />
    
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
            ConnectionString="<%$ ConnectionStrings:NORTHWINDConnectionString %>" 
            SelectCommand="SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued] 
                           FROM [Products] WHERE ([UnitPrice] &gt;= @UnitPrice)" 
            OnSelecting="SqlDataSource1_Selecting">
            <SelectParameters>
                <asp:Parameter Name="UnitPrice" Type="Decimal" DefaultValue="0" />
            </SelectParameters>
        </asp:SqlDataSource>
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ProductID" DataSourceID="SqlDataSource1">
            <Columns>
                <asp:BoundField DataField="ProductID" HeaderText="ProductID" 
                    InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
                <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
                    SortExpression="UnitPrice" />
                <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" 
                    SortExpression="Discontinued" />
            </Columns>
        </asp:GridView>
    </asp:Content>

    結果は以下のようになります。

    2020年6月30日 2:21

すべての返信

  • 開発環境(Visual Studio, .NET Framework のバージョン、DB を使っているならそれが何かとバージョン・エディションなど)を書いてください。

    SqlDataSource のデータはどのようになっているのですか? DB のテーブルから取得しているなら、そのテーブルの構造を書いてください。そうでなくて何か他のものをデータソースにしているなら、同等の情報が分かるようにしてください。

    で、肝心の質問ですが、

    > SQL文中に"@price"のSelectParameterがあり、CheckBoxのチェック有無により、@priceの金額をパラメータとして設定したい状況です。

    というのが理解できません。ここに書いてあること以外は知り得ない第三者が読んで分かるように書かれているとは思えないのですが? もう少し、具体的に説明できないですか?

    • 編集済み SurferOnWww 2020年6月29日 8:44 追記
    2020年6月29日 8:38
  • 返信いただき、ありがとうございます。

    環境は、Visual Studio Community 2019で、databaseは開発環境中のMSSQLLocalDBです。
    .NET Framework4.8でWEBフォームを作成しています。

    SQLはごく単純に書けば、select * from hoge where price>=@price という感じです。
    aspx中にChechBoxを配置しており、それがCheckedであれば「0」を、Checkedでなければ例えば「1000」を@priceにパラメータとして渡したい、というところです。

    そこで、質問のコードを書きましたが、例外が発生してしまう、というご相談となります。

    2020年6月29日 9:07
  • 分かりません。

    問題を再現できる必要最低限に絞ったコードをアップしてください。

    2020年6月29日 10:31
  • 自分ならこうするという案を勝手に書いておきます。

    > 問題を再現できる必要最低限に絞ったコードをアップしてください。

    上記の依頼に反応がなく、質問者さんのやりたいことの詳細は不明ですので、質問者さんの意向には沿わないかもしれませんが。

    where 句に設定するのが金額なので、表題の「SqlDataSourceのパラメータとしてCheckBoxを使いたい」は無理です。

    どうしてもということなら、ストアドプロシージャを作ってそれに ture / false を渡し、ストアドプロシージャの中で ture / false を金額に変換して where 句に設定するということが思いつきますが、そこまでやる気は多分ないだろうと思います。

    なので、ASP.NET のコードビハインドでチェックの有無を金額に変換して where 句のパラメータに代入するのがよさそうです。それはたぶん質問者さんもそう考えたのだろうと思います。

    > SqlDataSource1_Selectingに記述しても同じです。

    とのことですので、もう一歩のところだったのかもしれませんね。

    以下のサンプルコードは、Microsoft の Northwind サンプルデータベースの Products テーブルを使って、CheckBox にチェックが入っている場合は UnitPrice が $40 以上の商品を選択するものです。

    詳しい説明はしませんが、不明点があれば質問してください。ただし、この方向で OK であればです。NG ならどこがやりたいことと違うのか、質問者さんのコードをアップするなどして詳しく説明してください。


    aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data.SqlClient;
    
    namespace WebApplication1
    {
        public partial class WebForm7 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
            {
                GridView1.DataBind();
            }
    
            protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
            {
                var command = (SqlCommand)e.Command;
                if (CheckBox1.Checked)
                {
                    command.Parameters["@UnitPrice"].Value = 40m;
                }
                else
                {
                    command.Parameters["@UnitPrice"].Value = 0m;
                }
            }
        }
    }

    .aspx

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" 
        AutoEventWireup="true" CodeBehind="WebForm7.aspx.cs" 
        Inherits="WebApplication1.WebForm7" %>
    
    <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
    </asp:Content>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
        <p>チェックを入れて Button クリックで Unit Price $40 以上の商品を選択</p>
        <asp:CheckBox ID="CheckBox1" runat="server" 
            OnCheckedChanged="CheckBox1_CheckedChanged" />    
        <asp:Button ID="Button1" runat="server" Text="Button" />
    
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
            ConnectionString="<%$ ConnectionStrings:NORTHWINDConnectionString %>" 
            SelectCommand="SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued] 
                           FROM [Products] WHERE ([UnitPrice] &gt;= @UnitPrice)" 
            OnSelecting="SqlDataSource1_Selecting">
            <SelectParameters>
                <asp:Parameter Name="UnitPrice" Type="Decimal" DefaultValue="0" />
            </SelectParameters>
        </asp:SqlDataSource>
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ProductID" DataSourceID="SqlDataSource1">
            <Columns>
                <asp:BoundField DataField="ProductID" HeaderText="ProductID" 
                    InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
                <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
                    SortExpression="UnitPrice" />
                <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" 
                    SortExpression="Discontinued" />
            </Columns>
        </asp:GridView>
    </asp:Content>

    結果は以下のようになります。

    2020年6月30日 2:21
  • SuferOnWww様

    アドバイスいただきながら返信遅くなり、申し訳ございません。
    例示いただいたコードを拝見し、試したところ、まさにこれで解決しました。
    困っていたのは、SqlDataSourceに対し、パラメータの値をどのようにコードビハインドから渡すかでした。

    私は、質問に書いたように、以下のコードで渡せると考えていたのですが、おっしゃる通り一歩足りなかったようです。

    Protected Sub SqlDataSource1_Selecting(sender As Object, e As SqlDataSourceSelectingEventArgs) Handles SqlDataSource1.Selecting
        SqlDataSource1.SelectParameters("price").DefaultValue = IIf(CheckBox1.Checked, "0", "1000")
    End Sub
    これを、上記のサンプルコードを参考に
    Protected Sub SqlDataSource1_Selecting(sender As Object, e As  SqlDataSourceSelectingEventArgs) Handles SqlDataSource1.Selecting
        e.Command.Parameters("@price").Value = IIf(CheckBox1.Checked, 0, 1000)
    End Sub
    これに替えたところ、思った通りの動作をしました。
    本当にありがとうございました。


    2020年6月30日 10:32