WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

DropDownList での NULL の処置

by WebSurfer 2015年10月23日 17:19

下の画像のように、GridView などでデータベースの更新操作を行う際 DropDownList を利用してユーザー入力に便宜を図ることがあると思います。その時、NULL を DropDownList でどう対処するかという話を書きます。

GridView 上の DropDownList

ここで紹介する例には Microsoft が提供している Northwind サンプルデータベースの Products テーブルと Categories テーブルを使用しています。

Products テーブルの中の ProductName, CategoryID フィールドを GridView 上で更新する際、CategoryID の列に DropDownList を表示するようにします。

DropDownList には、ユーザーが見ても何だか分からない数字 (CategoryID) を表示するのでははなくて、ユーザーが読んで理解できる名前 (CategoryName) を Categories テーブルから取得して表示します。

Products テーブルの CategoryID には以下のような外部キー制約がかかっていますので、Categories テーブルの CategoryID の値(Northwind サンプルデータベースでは 1 から 8)以外のものは入力できません。

ALTER TABLE [dbo].[Products]  
  ADD CONSTRAINT [FK_Products_Categories] 
  FOREIGN KEY([CategoryID])
  REFERENCES [dbo].[Categories] 
  ([CategoryID])

ただし、NULL は許可されていますので、1 から 8 以外に NULL が入っていることがあります。また、更新の際に NULL を入力したいというケースもあるかもしれません。

先の記事 GridView 上の DropDownList に ToolTip でも同様に DropDownList を使用していますが、そこでは NULL 対応は考えていませんでした。それを以下ように修正して NULL に対応します。

  1. SELECT クエリで INNER JOIN 句に替えて LEFT OUTER JOIN 句を使い CategoryID が NULL のレコードも抽出する。
  2. DropDownList で AppendDataBoundItems="True" とし、以下のような NULL 用の ListItem を追加する。

    <asp:ListItem Value="">NULL</asp:ListItem>

    Value は空白("")にしてください。DropDownList に表示される文字列 NULL は任意のものに変えていいです。データベース上での NULL と ASP.NET コントロール上での空白("")の変換は、ASP.NET の組み込み機能を利用します。その機能についての説明は MSDN ライブラリの記事データ ソース コントロールを使用した、データベースの Null 値の処理を見てください。

具体的なコードは以下の通りです。(分かりやすくするため、先の記事 GridView 上の DropDownList に ToolTip のコードの ToolTip を設定する部分は省いています)

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind2 %>" 
      SelectCommand=
        "SELECT TOP 10 
        p.[ProductID], p.[ProductName], 
        p.[CategoryID], c.[CategoryName] 
        FROM [Products] AS p 
        LEFT OUTER JOIN [Categories] AS c 
        ON p.[CategoryID] = c.[CategoryID]
        ORDER BY p.[ProductID]" 
      UpdateCommand=
        "UPDATE [Products] 
        SET [ProductName] = @ProductName, 
        [CategoryID] = @CategoryID 
        WHERE [ProductID] = @ProductID">
      <UpdateParameters>
        <asp:Parameter Name="ProductID" Type="Int32" />
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="CategoryID" Type="Int32" />
      </UpdateParameters>
    </asp:SqlDataSource>

    <asp:SqlDataSource ID="SqlDataSource2" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind2 %>" 
      SelectCommand=
        "SELECT [CategoryID], [CategoryName], [Description] 
        FROM [Categories]">
    </asp:SqlDataSource>
        
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False" 
      DataKeyNames="ProductID" 
      DataSourceID="SqlDataSource1">
      <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductID" 
          HeaderText="ID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" 
          HeaderText="Product Name" 
          SortExpression="ProductName" />
        <asp:TemplateField HeaderText="Category" 
          SortExpression="CategoryName">
          <EditItemTemplate>                        
            <asp:DropDownList ID="DropDownList1" 
              runat="server" 
              DataSourceID="SqlDataSource2" 
              DataTextField="CategoryName" 
              DataValueField="CategoryID" 
              SelectedValue='<%# Bind("CategoryID") %>' 
              AppendDataBoundItems="True">
              <asp:ListItem Value="">NULL</asp:ListItem>
            </asp:DropDownList>
          </EditItemTemplate>
         <ItemTemplate>
            <asp:Label ID="Label1" 
              runat="server" 
              Text='<%# Bind("CategoryName") %>'>
            </asp:Label>
          </ItemTemplate>
        </asp:TemplateField>
      </Columns>
    </asp:GridView>
  </div>
  </form>
</body>
</html>

Tags: , ,

ASP.NET

GridView 上の DropDownList に ToolTip

by WebSurfer 2013年11月2日 18:33
注意:
以下の記事の例では、Products テーブルの CategoryID が NULL の場合、および更新の際に NULL を入力する場合の対応は考えていません。NULL 対応は別の記事 DropDownList での NULL の処置 を見てください。

GridView などで更新操作を行う際、DropDownList を利用してユーザー入力に便宜を図ることがあります。その際、ツールチップを利用して DropDownList 上の各項目の説明を表示するという話です。

GridView 上の DropDownList に ToolTip 表示

ここで紹介する例には Microsoft が提供している Northwind サンプルデータベースの Products テーブルと Categories テーブルを使用しています。

Products テーブルの中の ProductName, CategoryID フィールドを GridView 上で更新する際、CategoryID の列に DropDownList を表示するようにします。

DropDownList には、ユーザーが見ても何だか分からない ID (CategoryID) を表示するのでははなくて、ユーザーが読んで理解できる名前 (CategoryName) を表示します。

さらに DropDownList を開いて項目一覧を表示し、それにマウスカーソルを当てると各項目の説明 (Description) をツールチップに表示するようにします。上の画像を見てください。

DropDownList が閉じている時に DropDownList にマウスカーソルを当てると、選択された項目の説明がツールチップに表示されるようにしています。

上の画像を表示したサンプルコードは以下の通りです。詳細はコメントに説明を書きましたので、それを参考にしてください。手抜きでスミマセン。(汗)

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  // DropDownList には RowDataBound や ItemDataBound に該当す
  // るイベントがないので、各項目にツールチップを追加するには
  // 以下のような方法を取らざるを得ない。
  // 
  // GridView の[編集]ボタンがクリックされるとポストバック
  // され、当該行内に DropDownList がレンダリングされる。その
  // 際に DropDownList.DataBound イベントが発生するので、そこ
  // で DropDownList およびその中の ListItem にツールチップを
  // 設定する。
  protected void DropDownList1_DataBound(object sender, 
        EventArgs e)
  {
      DropDownList ddl = (DropDownList)sender;

      // 再度 DB にクエリを投げてデータを取得。(他に方法が
      // 見つからない)
      DataView dv = (DataView)SqlDataSource2.
            Select(DataSourceSelectArguments.Empty);

      foreach (ListItem item in ddl.Items)
      {
          dv.RowFilter = 
                String.Format("CategoryID='{0}'", item.Value);
          string description = (string)dv[0]["Description"];
            
          // ListItem には ToolTip プロパティはないので、直接
          // title 属性に description を設定する。
          item.Attributes["title"] = description;

          // DropDownList の ToolTip には、選択されている項目の
          // description を設定する。
          if (item.Selected)
          {
              ddl.ToolTip = description;
          }
      }

      // ユーザーが DropDownList 中の項目をクリックして選択され
      // ている項目を変更した場合、それに応じて DropDownList の
      // ToolTip を書き換えるためのスクリプトを追加        
      string csname1 = "jQuery1.8.3";
      string csurl = "~/Scripts/jquery-1.8.3.js";
      string csname2 = "ChangeDropDownListToolTipScript";
      Type cstype = this.GetType();
      ClientScriptManager cs = Page.ClientScript;

      // jQuery を利用するので参照を追加。
      if (!cs.IsClientScriptIncludeRegistered(cstype, csname1))
      {
          cs.RegisterClientScriptInclude(
                cstype, csname1, ResolveClientUrl(csurl));
      }

      // DropDownList の ToolTip 書き換え用スクリプト追加。
      if (!cs.IsClientScriptBlockRegistered(cstype, csname2))
      {
          StringBuilder cstext = new StringBuilder();
          cstext.Append("$(function () {");
          cstext.Append("$('#" + ddl.ClientID + "').change(");
          cstext.Append("function () {");
          cstext.Append("$(this).attr('title', $('#" +
                ddl.ClientID +
                " option:selected').attr('title'));");
          cstext.Append("});");
          cstext.Append("});");
          cs.RegisterClientScriptBlock(
              cstype, csname2, cstext.ToString(), true);
      }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT TOP 10 
          p.[ProductID], p.[ProductName], 
          p.[CategoryID], c.[CategoryName] 
        FROM [Products] AS p 
        INNER JOIN [Categories] AS c 
        ON p.[CategoryID] = c.[CategoryID] 
        ORDER BY p.[ProductID]" 
      UpdateCommand=
        "UPDATE [Products] 
        SET [ProductName] = @ProductName, 
            [CategoryID] = @CategoryID 
        WHERE [ProductID] = @ProductID">
      <UpdateParameters>
        <asp:Parameter Name="ProductID" Type="Int32" />
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="CategoryID" Type="Int32" />                
      </UpdateParameters>
    </asp:SqlDataSource>

    <asp:SqlDataSource ID="SqlDataSource2" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT [CategoryID], [CategoryName], [Description] 
        FROM [Categories]">
    </asp:SqlDataSource>
        
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False" 
      DataKeyNames="ProductID" 
      DataSourceID="SqlDataSource1">
      <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductID" 
          HeaderText="ID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" 
          HeaderText="Product Name" 
          SortExpression="ProductName" />
        <asp:TemplateField HeaderText="Category" 
          SortExpression="CategoryName">
          <EditItemTemplate>                        
            <asp:DropDownList ID="DropDownList1" 
              runat="server" 
              DataSourceID="SqlDataSource2" 
              DataTextField="CategoryName" 
              DataValueField="CategoryID" 
              SelectedValue='<%# Bind("CategoryID") %>' 
              OnDataBound="DropDownList1_DataBound">
            </asp:DropDownList>
          </EditItemTemplate>
          <ItemTemplate>
            <asp:Label ID="Label1" 
              runat="server" 
              Text='<%# Bind("CategoryName") %>'>
            </asp:Label>
          </ItemTemplate>
        </asp:TemplateField>
      </Columns>
    </asp:GridView>
  </div>
  </form>
</body>
</html>

Tags: , ,

ASP.NET

DropDownList を使って絞込み

by WebSurfer 2011年7月17日 14:29

GridView に表示するレコードを DropDownList を使って絞り込むサンプルです。

GridView に表示するレコードを DropDownList を使って絞り込み

以前、実験室 SelectCommand の切り替え にも、2 つの DropDownList を使って GridView に表示されるレコードを絞り込むサンプルを書きましたが、それは SqlDataSource の SelectCommand(正確には SELECT クエリの WHERE 句)を書き換えていて、そのためのコードを書かなければならないのが面倒で、かつ、あまりスマートな方法とはいえません。

今回、ここに書いた方法は、WHERE 句は以下のように固定しておいて、DropDownList の SelectedValue プロパティの値によって全件抽出と条件抽出の両方に対応できるようにしたものです。

WHERE (@CustomerID='ALL' OR o.CustomerID=@CustomerID) 
  AND (@EmployeeID=0 OR e.EmployeeID=@EmployeeID)

上記で、@CustomerID='ALL' と @EmployeeID=0 が全件抽出の条件で、DropDownList.SelectedValue がそれぞれ "ALL" と "0" の時にその条件に一致させるようにします。

そのために、DropDownList の AppendDataBoundItems プロパティを true に設定した上で、全件抽出条件のための ListItem を追加します。なお、EmployeeID については、データ型が int なので、ListItem は以下のように設定しなければなりません。DropDownList.SelectedValue プロパティは string 型を返しますが、データベースプロバイダが型変換してくれます。

<asp:ListItem Value="0">ALL</asp:ListItem>

これによって C# のコードは一行も書かずに、すべてウィザードベースで作ることができます。上の画像の aspx ページのコードは以下の通りです。データベースには Northwind サンプルデータベースの Orders, Customers, Employees テーブルを使っています。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT DISTINCT o.CustomerID, c.CompanyName 
        FROM Orders AS o 
        INNER JOIN Customers AS c 
        ON o.CustomerID = c.CustomerID">
    </asp:SqlDataSource>
    Customer: 
    <asp:DropDownList ID="DropDownList1" 
      runat="server" 
      AppendDataBoundItems="True" 
      DataSourceID="SqlDataSource1" 
      DataTextField="CompanyName" 
      DataValueField="CustomerID" 
      AutoPostBack="True">
      <asp:ListItem>ALL</asp:ListItem>
    </asp:DropDownList>
    <br />
    <asp:SqlDataSource ID="SqlDataSource2" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT DISTINCT o.EmployeeID, 
          e.FirstName + ' ' + e.LastName AS Name 
        FROM Orders AS o 
        INNER JOIN Employees AS e 
        ON o.EmployeeID = e.EmployeeID">
    </asp:SqlDataSource>
    Employee: 
    <asp:DropDownList ID="DropDownList2" 
      runat="server" 
      AppendDataBoundItems="True" 
      DataSourceID="SqlDataSource2" 
      DataTextField="Name" 
      DataValueField="EmployeeID" 
      AutoPostBack="True">
      <asp:ListItem Value="0">ALL</asp:ListItem>
    </asp:DropDownList>

    <asp:SqlDataSource ID="SqlDataSource3" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT o.OrderID, c.CompanyName, 
          e.FirstName + ' ' + e.LastName AS Name, 
          o.ShippedDate, o.Freight 
        FROM Orders AS o 
        INNER JOIN Customers AS c 
          ON o.CustomerID = c.CustomerID 
        INNER JOIN Employees AS e 
          ON o.EmployeeID = e.EmployeeID
        WHERE (@CustomerID='ALL' OR o.CustomerID=@CustomerID) 
          AND (@EmployeeID=0 OR e.EmployeeID=@EmployeeID)
        ORDER BY o.OrderID">
        <SelectParameters>
          <asp:ControlParameter ControlID="DropDownList1" 
            Name="CustomerID" 
            PropertyName="SelectedValue" />
          <asp:ControlParameter ControlID="DropDownList2" 
            Name="EmployeeID" 
            PropertyName="SelectedValue" />
        </SelectParameters>
    </asp:SqlDataSource>
    <asp:GridView ID="GridView1" 
      runat="server" 
      AllowPaging="True" 
      AutoGenerateColumns="False" 
      DataKeyNames="OrderID" 
      DataSourceID="SqlDataSource3">
      <Columns>
        <asp:BoundField 
          DataField="OrderID" 
          HeaderText="OrderID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="OrderID" />
        <asp:BoundField 
          DataField="CompanyName" 
          HeaderText="Customer" 
          SortExpression="CompanyName" />
        <asp:BoundField 
          DataField="Name" 
          HeaderText="Employee" 
          ReadOnly="True" 
          SortExpression="Name" />
        <asp:BoundField 
          DataField="ShippedDate" 
          HeaderText="Shipped Date" 
          SortExpression="ShippedDate" 
          DataFormatString="{0:yyyy/M/d}" >
          <ItemStyle HorizontalAlign="Center" />
        </asp:BoundField>
        <asp:BoundField 
          DataField="Freight" 
          HeaderText="Freight" 
          SortExpression="Freight" 
          DataFormatString="${0:N2}" >
          <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
      </Columns>
    </asp:GridView>
  </div>
  </form>
</body>
</html>

Tags: ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年6月  >>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

View posts in large calendar