質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

1回答

3958閲覧

GridViewのデータテーブルがnullになってしまう

退会済みユーザー

退会済みユーザー

総合スコア0

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2020/07/03 15:04

編集2020/07/05 04:37

前提・実現したいこと

GridViewを使用してWebアプリケーションを作成しています。
GridViewにはMySQLを使用しテーブルを表示しておりますが、データテーブルには情報が入っていないようで(GridViewには表示されているので、表示後破棄されている?)、削除ボタンが機能しません。

行の「選択」ボタンを押し、削除ボタンを押すと行が削除されるようにしたいのですが、「選択」ボタンを押したときエラーが出てしまいました。(削除ボタンはスマートタグを使用せずコーディングする予定なので、下のコードになっています。)
(System.NullReferenceException: 'オブジェクト参照がオブジェクト インスタンスに設定されていません。'dt が null でした。)

該当のソースコード

●Window1(~.aspx) <%@ Page Language="C#" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="MySql.Data.MySqlClient" %> <%@ Import Namespace="System.Configuration" %> <script runat="server"> protected void Page_Load(Object source, EventArgs e) { if (IsPostBack) { return; } DataCatch(); } DataTable dt; int selectRow; protected void Button1_Click(object sender, EventArgs e) //編集 { Response.Redirect("~/edit.aspx"); } protected void Button2_Click(object sender, EventArgs e) //削除 { Button2.Attributes["onclick"] = "return confirm('削除しますか?');"; DataRow dr = dt.Rows[GridView1.SelectedIndex]; dr.Delete(); } protected void Button3_Click(object sender, EventArgs e) //追加 { Response.Redirect("~/edit.aspx"); } private void DataCatch() { //接続文字列を取得 string dbn = ConfigurationManager.ConnectionStrings["db"].ConnectionString; MySqlConnection cn = new MySqlConnection(dbn); cn.Open(); //SQL文と接続情報を指定しアダプタ作成 MySqlDataAdapter da = new MySqlDataAdapter("select * from ***", cn); //データ格納のためデータセット作成 DataSet dataSet = new DataSet(); //データ格納のためテーブル作成 dt = new DataTable(); dataSet.Tables.Add(dt); //取得 da.Fill(dt); cn.Close(); // GridViewとバインド GridView1.DataSource = new DataView(dt); DataBind(); } </script> <script type="text/javascript"> function winClose() { window.open('','_self').close(); } </script> <html> <body> <form id="form1" runat="server"> <div>*** <hr/> <br/> <asp:Button ID="Button1" runat="server" Text="編集" OnClick="Button1_Click" />  <asp:Button ID="Button2" runat="server" Text="削除" OnClick="Button2_Click"/>  <asp:Button ID="Button3" runat="server" Text="追加" OnClick="Button3_Click"/>  <input type="button" onclick="winClose()" value="終了" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> <br /> </div> <p> &nbsp;</p> <asp:GridView id="GridView1" runat="server" OnRowDeleting="Button2_Click" OnSelectedIndexChanged="Button2_Click" > <Columns> <asp:CommandField ShowSelectButton="True" /> </Columns> </asp:GridView> </form> </body> </html>

補足情報(FW/ツールのバージョンなど)

ASP.NET
Visual Studio2019
C#
.NET Framework4.7.2

追記(2020.7.5)

回答を受け、修正しました。

<%@ Page Language="C#" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="MySql.Data.MySqlClient" %> <%@ Import Namespace="System.Configuration" %> <script runat="server"> protected void Page_Load(Object source, EventArgs e) { if (IsPostBack) { return; } DataCatch(); } DataTable dt; int selectRow; protected void Button1_Click(object sender, EventArgs e) //編集 { Response.Redirect("~/edit.aspx"); } protected void Button2_Click(object sender, EventArgs e) //削除 { int selectV = (int)GridView1.SelectedValue; //delete from *** where type='@selectV'; } protected void Button3_Click(object sender, EventArgs e) //追加 { Response.Redirect("~/edit.aspx"); } private void DataCatch() { //接続文字列を取得 string dbn = ConfigurationManager.ConnectionStrings["db"].ConnectionString; MySqlConnection cn = new MySqlConnection(dbn); cn.Open(); //SQL文と接続情報を指定しアダプタ作成 MySqlDataAdapter da = new MySqlDataAdapter("select * from ***", cn); //データ格納のためデータセット作成 DataSet dataSet = new DataSet(); //データ格納のためテーブル作成 dt = new DataTable(); dataSet.Tables.Add(dt); //取得 da.Fill(dt); cn.Close(); // GridViewとバインド GridView1.DataSource = new DataView(dt); DataBind(); } </script> <script type="text/javascript"> function winClose() { window.open('', '_self').close(); } </script> <html> <body> <form id="form1" runat="server"> <div>*** <hr/> <br/> <asp:Button ID="Button1" runat="server" Text="編集" OnClick="Button1_Click" />  <asp:Button ID="Button2" runat="server" Text="削除" OnClick="Button2_Click" OnClientClick="return confirm('削除しますか?')"/>  <asp:Button ID="Button3" runat="server" Text="追加" OnClick="Button3_Click"/>  <input type="button" onclick="winClose()" value="終了" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> <br /> </div> <p> &nbsp;</p> <asp:GridView id="GridView1" runat="server" DataKeyNames="id" > <Columns> <asp:CommandField ShowSelectButton="True" /> </Columns> </asp:GridView> </form> </body> </html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/07/03 21:32 編集

コードは ``` と ``` で囲ってください (``` はバッククォート 3 つ)。インデントされて見やすくなるので。 あと、できれば GridView のスタイル関係のコードは削除願います。
退会済みユーザー

退会済みユーザー

2020/07/03 21:56

> 「選択」ボタンを押したときエラーが出てしまいました。 削除ボタンの間違いですか? 質問者さん、どのぐらい ASP.NET Web アプリの開発経験があるのでしょう? 初心者とお見受けしますが、であれば初心者マークを付けるとかその旨書くようお願いします。
退会済みユーザー

退会済みユーザー

2020/07/03 22:12

コメントありがとうございます。 ご指摘いただいた点修正いたしました。 ボタンは「選択ボタン」です。選択を押すとエラーが出てしまいます。
退会済みユーザー

退会済みユーザー

2020/07/03 22:25 編集

> ボタンは「選択ボタン」です。 「選択」ボタンのクリックで dt が null になると言うエラーが出るのが解せません。コードのどの行でそのエラーが出るのですか?
退会済みユーザー

退会済みユーザー

2020/07/03 22:35

DataRow dr = dt.Rows[GridView1.SelectedIndex]; でエラーになります。
退会済みユーザー

退会済みユーザー

2020/07/03 22:50

そのコードは Button2 (「削除」ボタンのはず) の Click イベントのハンドラの中にあるものですよね? そして、「選択」ボタンというのは GridView の中にある CommandField のボタンのことですよね。 だとすると、「選択」ボタンクリックで問題のコードに制御が飛んで来ることはないはず。何か特別なことをしてますか?
退会済みユーザー

退会済みユーザー

2020/07/03 22:59

はい、そうです。Button2の削除ボタンにあるものです。 選択ボタンは、おっしゃる通りGridViewの中にあるCommandFieldのボタンです。 GridViewのRowDeletingとSelectedIndexChangedイベントをButton2に設定していますが関係ありますでしょうか?
退会済みユーザー

退会済みユーザー

2020/07/03 23:29

話が違いますね。質問文では、 > 行の「選択」ボタンを押し、削除ボタンを押すと行が削除されるようにしたいのですが ・・・と書いてあって、2 段階で削除するのだと思ってます。違うのですか?
退会済みユーザー

退会済みユーザー

2020/07/03 23:36

その通りです。 自分でコードを書くとき、いろいろと調べている段階で、イベントを追加することで削除できるのではと思考錯誤しておりました。
退会済みユーザー

退会済みユーザー

2020/07/03 23:47 編集

基本的な問題が色々あって期待通りにはいくはずがないところに、上手くいかないからよく分からないまま色々試して、事態が悪化している感じです。 大体やっていることは分かりましたので、後で解答欄に問題点と対応策を書いておきます。ちょっと問題が多いので書くのに時間がかかりそうです。少しお待ちください。
退会済みユーザー

退会済みユーザー

2020/07/03 23:56

すみません。 本当にありがとうございます。 よろしくお願いいたします。
guest

回答1

0

ベストアンサー

ちょっと問題が多いので、列挙して対応案を書いておきます。その前に確認ですが対象の MySQL のテーブルには主キーはあるのですよね? 無いと何ともならないので、もし無ければ追加してください

(1) SqlDataSource を使いましょう

特に事情がなければ、SqlDataSource または ObjectDataSource と組み合わせて使うように方針変更することをお勧めします。

そうすれば、自力でコードを全く書かなくても、デザイナで MySQL のテーブルの一覧表示、編集を行うアプリを非常に簡単に作成することができます。開発工数も保守工数も激減するはずです。

方針変更による後戻り工数は発生するかもしれませんが、この先また起こるであろう問題の対応に工数を使うよりはよさそうです。

(2) Web アプリはステートレス

今のコードではポストバックされたときにはサーバー側には DataTable は存在しません。

最初の要求でサーバーが初期画面を作る際 MySQL からデータを取得し DataTable を作成して GridView にバインドしていますが、応答をブラウザに返した後は、サーバーは初期画面を作るためにメモリにロードしたもろもろ(DataTable のインスタンスを含む)をすべて消去します。

ボタンクリックでポストバックされますが、その時は DataCatch() メソッドは動かない(そういうコードになっています)ので DataTable は作られません。なのでボタンクリックでポストバックされたときは変数 dt は null です。

それでも GridView には一覧が表示されるのは ViewState に前の画面の情報が保持されていて、それを使って表示されるからです。

だからと言って、ポストバックの際も毎回 DataCatch() メソッドを動くようにして MySQL からデータを取得して DataTable を作成するのは悪手ですのでそれはやらないようにしましょう

(3) GridView の OnRowDeleting, OnSelectedIndexChanged

上手くいかないからよく分からないままいろいろ試していて、OnRowDeleting, OnSelectedIndexChanged もその一つとして追加したと理解しています。

質問文では、

行の「選択」ボタンを押し、削除ボタンを押すと行が削除されるようにしたいのですが

・・・と書いてあって、2 段階で削除するということですが、それなら不要ですので削除してください。

(4) Button2_Click の処置

dr.Delete(); は DataTable の当該行に削除マークを付けるだけです。MySQL には何の影響もなく、当然レコードの削除もできません。

上記 (3) の処置で「削除」ボタンのクリックだけでこのハンドラに制御が飛ぶようにしたら、以下のように変更してみてください。

(4-1) Button2.Attributes["onclick"] = "return confirm('削除しますか?');"; は削除。代わりに Button2 の OnClientClick プロパティに JavaScript を設定。

(4-2) GridView.SelectedValue プロパティで選択されている行の主キー値を取得できるようする。(SELECT クエリに主キーを含めることと、GridView の DataKeyNames の設定が必要)

(4-3) DataRow dr = dt.Rows[GridView1.SelectedIndex]; と dr.Delete(); も削除。代わりに GridView.SelectedValue プロパティで主キーを取得し ADO.NET + Connector/NET のコードを書いて DELETE 文を MySQL に発行し、削除する)

(4-4) GridView.DataBind() で削除後のデータを MySQL から取得して表示できるようにする。

他にも問題はいろいろありそうですが、とりあえずこれで削除はできるようになると思います。

不明点があればこの回答のコメント欄で質問してください。

【追記】

下のコメント欄の 2020/07/05 16:22 の私のコメントで、「そのためには DataCatch() メソッドのコードを直した方がよさそうです。質問にあるコードは問題もあるので、その修正案と合わせて後で回答欄に追記しておきます。」と書きましたがそれを以下に書きます。

質問者さんの DataCatch() メソッドは、(1) DataTable(または DataView)を返すように変更、(2) SELECT クエリは SELECT * FROM ... のように * は使わないで * の部分にはフィールド名を明記する、(3) 接続の Open / Close は書かないで MySqlDataAdapter に任せる(自動的に行われます)、(4) MySqlConnection の初期化のコードには using 句を使って確実に Dispose されるようにする(特に Button2_Click では必須) ・・・と言うように変更した方がよさそうです。

それを Page_Load で初期画面のデータを取得する際と、Button2_Click で削除後のデータを取得する際に GridView の DataSource プロパティに設定して、そのあとで GridView.DataBind() としてください。

以下のような感じです。

C#

1using System; 2using System.Data; 3using MySql.Data.MySqlClient; 4 5namespace WebApplication1 6{ 7 public partial class WebForm8 : System.Web.UI.Page 8 { 9 protected void Page_Load(object sender, EventArgs e) 10 { 11 if (!IsPostBack) 12 { 13 GridView1.DataSource = DataCatch(); 14 GridView1.DataBind(); 15 } 16 } 17 18 protected DataTable DataCatch() 19 { 20 var table = new DataTable(); 21 var query = "SELECT Id, xxx, yyy, zzz FROM tableA"; 22 var connString = "接続文字列(省略)"; 23 using (var connection = new MySqlConnection(connString)) 24 { 25 var adapter = new MySqlDataAdapter(); 26 adapter.SelectCommand = new MySqlCommand(query, connection); 27 adapter.Fill(table); 28 return table; 29 } 30 } 31 32 protected void Button2_Click(object sender, EventArgs e) 33 { 34 int selectV = (int)GridView1.SelectedValue; 35 36 var query = "DELETE FROM tableA WHERE Id=@Id"; 37 var connString = "接続文字列(省略)"; 38 39 using (var connection = new MySqlConnection(connString)) 40 { 41 using (var command = new MySqlCommand(query, connection)) 42 { 43 command.Parameters.Add("@Id", MySqlDbType.Int32); 44 command.Parameters["@Id"].Value = selectV; 45 connection.Open(); 46 command.ExecuteNonQuery(); 47 } 48 } 49 50 GridView1.DataSource = DataCatch(); 51 GridView1.DataBind(); 52 } 53 } 54}

投稿2020/07/04 01:26

編集2020/07/05 07:52
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/07/04 01:59

回答ありがとうございます。 初歩的な質問であると思うのですが、SqlDataSourceのデータソース構成で、データソース欄にmysqlが出てこないの原因は何が考えられるのでしょうか。
退会済みユーザー

退会済みユーザー

2020/07/04 02:10

MySQL for Visual Studio がインストールされてないか、インストールされていても無効化されているからだろうと思います。Visual Studio の拡張機能の管理をチェックしてみてください。 そもそも、MySQL の本体はどのようにインストールしたのですか? インストーラーを使ったのであれば、その時一緒にインストールしなかったのでしょうか? http://surferonwww.info/BlogEngine/post/2020/04/20/installation-of-mysql-on-new-desktop-pc.aspx
退会済みユーザー

退会済みユーザー

2020/07/04 02:17

コントロールパネルを確認し、MySQL Connector Net 8.0.19はインストールされています。
退会済みユーザー

退会済みユーザー

2020/07/04 02:19

コメントした後にSurferOnWww様のコメント見ました。投稿が被ってしまったようです。確認してみます。
退会済みユーザー

退会済みユーザー

2020/07/04 03:09

始めにMySQLをインストールしたとき、研修中に指示のままインストールしたものでしたので確認に少し時間がかかりそうです。もう少しだけお付き合いいただけたら幸いです。
退会済みユーザー

退会済みユーザー

2020/07/05 01:30

上の回答に書いた (1) に方針変更して、このスレッドの質問の直接の対応 (2) ~ (4) はもう止めにするのですか?
退会済みユーザー

退会済みユーザー

2020/07/05 02:54

(1)ですが、昨日思考錯誤しましたが対応ができなかったので、(2)~(4)をしていきたいと思います。遅くなりました。 (4-3)のGrivView.SelectedValueで主キー取得ができましたが、「ADO.NET + Connector/NET のコードを書いて DELETE 文を MySQL に発行し、削除する」がよく分からず、詰まってしまいました。
退会済みユーザー

退会済みユーザー

2020/07/05 03:06

> (1)ですが、昨日思考錯誤しましたが対応ができなかったので、 であれば、それは今後の課題として別に新たにスレッドを立てて質問していただければと思います。 > (4-3)のGrivView.SelectedValueで主キー取得ができましたが、「ADO.NET + Connector/NET のコードを書いて DELETE 文を MySQL に発行し、削除する」がよく分からず、詰まってしまいました。 質問欄を編集して、(2) ~ (4) の対応ができたところまでのコードを追記(追記でお願いします。元のコードはそのままにしておいてください)してもらえれば何かアドバイスができるかも。
退会済みユーザー

退会済みユーザー

2020/07/05 03:42

追記の前に一つ確認です。 (3)で、OnSelectedIndexChangedを削除と記載いただいていますが、SelectedValuesを取得するためにButton2にOnSelectedIndexChangedを設定して取得したのですが、このまま追記してもよいですか?
退会済みユーザー

退会済みユーザー

2020/07/05 04:13

行の「選択」ボタンを押し、削除ボタンを押すと行が削除されるという 2 段階で処理したかったのではないのですか? SelectedIndexChanged イベントのハンドラを Button2_Click にしたらどうなるかは理解したと思っていたのですが・・・
退会済みユーザー

退会済みユーザー

2020/07/05 04:24

再度Microsoftのドキュメントをしっかり読みなおし、selectedIndexChangedは削除しました。 これから追記に掲載いたします。
退会済みユーザー

退会済みユーザー

2020/07/05 04:51

質問欄の追記したコードの Button1_Click メソッドの int selectV に主キー値が取得できているのであれば、回答に書いた、 > ADO.NET + Connector/NET のコードを書いて DELETE 文を MySQL に発行し、削除する というところは、基本、以下の記事にあるようなコードになります。ググれば他にもいろいろ見つかると思いますので自分でも探してみてください。 第3回 .NETデータ・プロバイダによるレコードの挿入/削除/更新 (3/3) https://www.atmarkit.co.jp/ait/articles/0307/12/news002_3.html 記事は SQL Server の場合ですが MySQL でもほとんど同じです。SqlConnection, SqlCommand は MySqlConnection, MySqlCommand に変更が必要ですが。 DataCatch() でデータが取得できているのであれば接続文字列は DataCatch() の中の string dbn = ... と同じコードで取得できるはずです。
退会済みユーザー

退会済みユーザー

2020/07/05 05:24

今気づきましたが、上のコメントで紹介した記事の cmd.Parameters.Add("@PubId", args[0]); ですが、そのオーバーロードは MySQL では使えないようです。以下のようにしてみてください。 cmd.Parameters.Add("@Id", MySqlDbType.Int32); cmd.Parameters["@Id"].Value = selectV;
退会済みユーザー

退会済みユーザー

2020/07/05 06:38

ありがとうございます。 現状、削除することができましたが、GridView1.DataBind()で再表示を試みたところ、GridViewが表示されませんでした。一度ブラウザを閉じ、再度GridViewを表示させたところ、選択した行は削除されておりました。
退会済みユーザー

退会済みユーザー

2020/07/05 07:22

> GridView1.DataBind()で再表示を試みたところ、GridViewが表示されませんでした。 回答の (4-4) で書いた「削除後のデータを MySQL から取得」というコードも書く必要があります。言葉足らずだったようですみません。 そのためには DataCatch() メソッドのコードを直した方がよさそうです。質問にある DataCatch() メソッドのコードは少々問題があるので、その修正案と合わせて後で回答欄に追記しておきます。
退会済みユーザー

退会済みユーザー

2020/07/05 07:31

何から何まで本当にありがとうございます。よろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2020/07/05 08:14

ありがとうございます。 選択行が削除され、GridViewの削除後の状態を表示できました。 これからコードを読み解いていきます。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問