none
EntityDataSource + ControlParameter + DropDownList の組み合わせで ListItem が増える RRS feed

  • 質問

  • http://bbs.wankuma.com/index.cgi?mode=al2&namber=51441 で質問していた件ですが、こちらに移動させて頂きます。

    環境は VS2008 SP1 C# です。

    以下のソースで、ページの初期表示時に titleList に同じデータが2つずつ表示されています。
    titleList の AppendDataBoundItems を true にするとさらに1組増えます。
    コードビハインドには何も書いていません。
    データベースは SQL Server 2008 R2 Developer 上の pubs です。
    http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=06616212-0356-46a0-8da2-eebc53a68034

    一度 publishers の選択を変えて、また初期状態に戻すと、正常に(重複なく)表示されます。
    titleList を ListBox や GridView に変えると再現しません。
    titlesDataSource の WhereParameters を削除したり、↓のように固定値にしても発生しなくなります。

    <asp:EntityDataSource ID="titlesDataSource" runat="server"
    	ConnectionString="name=PubsEntities" DefaultContainerName="PubsEntities" 
    	EntitySetName="titles"
    	Where="it.publishers.pub_id=@pub_id">
    	<WhereParameters>
    		<asp:Parameter Name="pub_id" Type="String" DefaultValue="0736" />
    	</WhereParameters>
    </asp:EntityDataSource>
    

    または

    <asp:EntityDataSource ID="titlesDataSource" runat="server"
    	ConnectionString="name=PubsEntities" DefaultContainerName="PubsEntities" 
    	EntitySetName="titles"
    	Where="it.publishers.pub_id='0736'">
    </asp:EntityDataSource>
    

    どなたか解消方法をご存知でしたら教えて頂けませんでしょうか。
    よろしくお願いいたします。

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="eds._Default" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    	<title></title>
    </head>
    <body>
    	<form id="form1" runat="server">
    	<div>
    		<asp:DropDownList ID="publisherList" runat="server" AutoPostBack="true"
    			DataSourceID="publishersDataSource" DataTextField="pub_name" DataValueField="pub_id">
    		</asp:DropDownList>
    
    		<asp:DropDownList ID="titleList" runat="server"
    			DataSourceID="titlesDataSource" DataTextField="title" DataValueField="title_id">
    		</asp:DropDownList>
    
    		<asp:EntityDataSource ID="publishersDataSource" runat="server"
    			ConnectionString="name=PubsEntities" DefaultContainerName="PubsEntities" EntitySetName="publishers">
    		</asp:EntityDataSource>
    
    		<asp:EntityDataSource ID="titlesDataSource" runat="server"
    			ConnectionString="name=PubsEntities" DefaultContainerName="PubsEntities" EntitySetName="titles"
    			AutoGenerateWhereClause="True">
    			<WhereParameters>
    				<asp:ControlParameter Name="publishers.pub_id" ControlID="publisherList" PropertyName="SelectedValue" />
    			</WhereParameters>
    		</asp:EntityDataSource>
    
    	</div>
    	</form>
    </body>
    </html>
    

    αετος(aetos)
    Microsoft MVP for Visual C++ Feb 2008 - Jun 2011
    http://www.aetosfolia.jp/
    http://aetosfolia.spaces.live.com/
    Microsoft Certified Technology Specialist
    Microsoft Certified Associate

    I bing. U bing ?
    2010年7月7日 4:32

回答

  • EntityDataSource は使ったことがない自分がレスするのもなんですが、気がついた
    点をレスします。

    一応目的の動作をするまで作ってみましたが、その過程で「titleList に同じデータ
    が2つずつ表示されています」ということは一度もなかったです。

    自分が作ったコードと aetos さんのコードを見比べてみてもほとんど同じですし、ど
    こに問題があるか分かりません。(自分が作ったコードは下にアップしておきます)

    違うのは、最初の表示のときに DropDownList.DataBind をしている点です(こうし
    ないと、最初の表示で DropDownList.SelectedValue が反映されない)。これがなく
    ても「titleList に同じデータが2つずつ表示されています」ということはないです
    が、一度試してみてください。

    その他、ADO.NET Entity Data Model (Model.edmx) がどのように作られているか不明
    ですが、それが異なるためかもしれませんね。

    ところで、何故 EntityDataSource を使っているのでしょうか? DropDownList を使
    ってこのようなことをするだけなら、何らメリットはなさそうな感じです。

    SqlDataSource を使う方がはるかに簡単かつ確実でいいと思うのですが。


    <%@ Page Language="C#" %>
    <%@ Register Assembly="System.Web.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        Namespace="System.Web.UI.WebControls" TagPrefix="asp" %>

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

    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                // 何故かこれがないと、最初の表示がうまくいかない。
                DropDownList1.DataBind();
                DropDownList2.DataBind();
            }
        }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:EntityDataSource ID="EntityDataSource1"
                runat="server"
                ConnectionString="name=PUBSEntities2"
                DefaultContainerName="PUBSEntities2"
                EntitySetName="publishers">
            </asp:EntityDataSource>
           
            <asp:DropDownList ID="DropDownList1"
                runat="server"
                AutoPostBack="True"
                DataSourceID="EntityDataSource1"
                DataTextField="pub_name"
                DataValueField="pub_id">
            </asp:DropDownList>
           
            <br />
           
            <asp:EntityDataSource ID="EntityDataSource2"
                runat="server"
                ConnectionString="name=PUBSEntities2"
                DefaultContainerName="PUBSEntities2"
                EntitySetName="titles"
                AutoGenerateWhereClause="True">
                <WhereParameters>
                    <asp:ControlParameter
                        ControlID="DropDownList1"
                        Name="publishers.pub_id"
                        PropertyName="SelectedValue" />
                </WhereParameters>
            </asp:EntityDataSource>
           
            <asp:DropDownList ID="DropDownList2"
                runat="server"
                DataSourceID="EntityDataSource2"
                DataTextField="title"
                DataValueField="title_id">
            </asp:DropDownList>
        </div>
        </form>
    </body>
    </html>

    • 回答としてマーク αετος 2010年7月12日 3:13
    2010年7月10日 12:30

すべての返信

  • EntityDataSource は使ったことがない自分がレスするのもなんですが、気がついた
    点をレスします。

    一応目的の動作をするまで作ってみましたが、その過程で「titleList に同じデータ
    が2つずつ表示されています」ということは一度もなかったです。

    自分が作ったコードと aetos さんのコードを見比べてみてもほとんど同じですし、ど
    こに問題があるか分かりません。(自分が作ったコードは下にアップしておきます)

    違うのは、最初の表示のときに DropDownList.DataBind をしている点です(こうし
    ないと、最初の表示で DropDownList.SelectedValue が反映されない)。これがなく
    ても「titleList に同じデータが2つずつ表示されています」ということはないです
    が、一度試してみてください。

    その他、ADO.NET Entity Data Model (Model.edmx) がどのように作られているか不明
    ですが、それが異なるためかもしれませんね。

    ところで、何故 EntityDataSource を使っているのでしょうか? DropDownList を使
    ってこのようなことをするだけなら、何らメリットはなさそうな感じです。

    SqlDataSource を使う方がはるかに簡単かつ確実でいいと思うのですが。


    <%@ Page Language="C#" %>
    <%@ Register Assembly="System.Web.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        Namespace="System.Web.UI.WebControls" TagPrefix="asp" %>

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

    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                // 何故かこれがないと、最初の表示がうまくいかない。
                DropDownList1.DataBind();
                DropDownList2.DataBind();
            }
        }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:EntityDataSource ID="EntityDataSource1"
                runat="server"
                ConnectionString="name=PUBSEntities2"
                DefaultContainerName="PUBSEntities2"
                EntitySetName="publishers">
            </asp:EntityDataSource>
           
            <asp:DropDownList ID="DropDownList1"
                runat="server"
                AutoPostBack="True"
                DataSourceID="EntityDataSource1"
                DataTextField="pub_name"
                DataValueField="pub_id">
            </asp:DropDownList>
           
            <br />
           
            <asp:EntityDataSource ID="EntityDataSource2"
                runat="server"
                ConnectionString="name=PUBSEntities2"
                DefaultContainerName="PUBSEntities2"
                EntitySetName="titles"
                AutoGenerateWhereClause="True">
                <WhereParameters>
                    <asp:ControlParameter
                        ControlID="DropDownList1"
                        Name="publishers.pub_id"
                        PropertyName="SelectedValue" />
                </WhereParameters>
            </asp:EntityDataSource>
           
            <asp:DropDownList ID="DropDownList2"
                runat="server"
                DataSourceID="EntityDataSource2"
                DataTextField="title"
                DataValueField="title_id">
            </asp:DropDownList>
        </div>
        </form>
    </body>
    </html>

    • 回答としてマーク αετος 2010年7月12日 3:13
    2010年7月10日 12:30
  • 追試ありがとうございます。

    再現手順を詳細に書いてみます。
    なお、DBはpubsが利用可能になっているものとします。

    1. VS2008 で新規プロジェクトを作成します。
      [Visual C#] > [Web] > [ASP.NET Web アプリケーション] です。
    2. プロジェクトに [ADO.NET Entity Data Model] を追加します。
      [データベースから生成] > [pubs] を選び、テーブルで publishers と titles を選択します。
      一度プロジェクトをビルドします。
    3. フォームに DropDownList を2つ、EntityDataSource を2つ配置します。
      DropDownListのIDはそれぞれ publisherList、titleList とします。
      EntityDataSourceのIDはそれぞれ publishersDataSource、titlesDataSource とします。
    4. publishersDataSource のデザイナメニューで [データ ソースの構成] を選びます。
      名前付き接続は pubsEntities 、EntitySetName は publishers とします。あとはデフォルトです。
      同様に titlesDataSource も構成します。EntitySetName が titles になる以外は同じです。
    5. titlesDataSource のプロパティで Where の右側の ... ボタンをクリックします。
      [指定されたパラメータを基に Where 式を自動生成する] をチェックします。
      [パラメータの追加] ボタンを押し、名前を publishers.pub_id、パラメータソースを Control、ControlID を publisherList とします。
    6. publisherList のデザイナメニューで [データ ソースの選択] を選びます。
      データソースは publishersDataSource、表示するデータ フィールドは pub_name、値のデータフィールドは pub_id です。
      また、デザイナメニューから [AutoPostBack を有効にする] をチェックします。
      同様に titlesList も構成します。
      データソースは titlesDataSource、表示するフィールドは title、値のフィールドは title_id です。
      こちらは AutoPostBack は有効にしません。
    7. デバッグ実行します。

    手順は以上です。コードは一切記述しておらず、すべて IDE での操作です。
    .cs も .aspx も手作業では一文字たりともいじっていません。

    この状態で、ブラウザ上では New Moon Books と You Can Combat Compurer Stress! が選択されています。
    titleList を見ると、You Can ... から Emotional Security ... までが2組表示されています。
    publishers で他のデータを選んでもそのようなことはなく、また、再び New Moon Books を選ぶと、やはり重複はありません。 

    違うのは、最初の表示のときに DropDownList.DataBind をしている点です(こうし
    ないと、最初の表示で DropDownList.SelectedValue が反映されない)。これがなく
    ても「titleList に同じデータが2つずつ表示されています」ということはないです
    が、一度試してみてください。

    これを試してみたところ解消しました。
    publishersList の DataBind だけでも大丈夫でした。
    ただ、こちらでは DataBind しなくても最初からデータは表示されています。

    また、フォームに Label と Button を置き、以下のようなコードを加えてみました。

    protected void Button1_Click(object sender, EventArgs e)
    {
     Label1.Text =
      (publisherList.SelectedItem == null ? "null" : publisherList.SelectedItem.Text) + ", " +
      (titleList.SelectedItem == null ? "null" : titleList.SelectedItem.Text);
    }
    
    結果、DataBind してもしなくても、この追加コードはうまく動作します("null" がでることはありませんでした)。
    SqlDataSource を使う方がはるかに簡単かつ確実でいいと思うのですが。

    まぁ SqlDataSource でもいいのですが…問題はとあるプロジェクトで発生しておりまして、そのプロジェクトでEDMを使うということになっているので、EntityDataSource かなぁ、と。特に考えもなくw


    αετος(aetos)
    Microsoft MVP for Visual C++ Feb 2008 - Jun 2011
    http://www.aetosfolia.jp/
    http://aetosfolia.spaces.live.com/
    Microsoft Certified Technology Specialist
    Microsoft Certified Associate

    I bing. U bing ?
    2010年7月12日 3:13
  • 先のレスで「その過程で『titleList に同じデータが2つずつ表示されています』という
    ことは一度もなかったです。」と書きましたが、見間違いでした。すみません。

    よく見てみれば、DataBind しない場合、titles の DropDownList には You Can Combat
    Computer Stress! から Emotional Security: New Algorithm までの5項目が繰り返し2
    回表示されていました。

    publishers の方の DropDownList には New Moon Books が選択され、中身も期待通り各
    項目が一つずつ表示されていました。

    最初の表示で DataBind しない場合は、aetos さんの結果と同じになっていたようです。

    DataBind の方も、両方の DropDownList で行う必要はなく、aetos さんが試された結果
    と同様に、publishers の方の DropDownList だけ DataBind すれば OK でした。

    2010年7月12日 14:08