WebSurfer's Home

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

DataGridView に ID と名前を併記

by WebSurfer 2014年2月1日 15:48

先の記事 DataGridView に ComboBox を表示 では CategoryID, SupplierID(数字)に代えて、名前を Categories, Suppliers テーブルから取得して ComboBox に表示する方法を書きました。

ComboBox など使わないで、ID と名前の両方を並べて表示すればよいというケースもあると思います。ここでは、Northwind サンプルデータベースの Products テーブルと Categories テーブルを例に使い、下の画像のように CategoryID と CategoryName を並べて表示する方法を書きます。なお、Visual Studio の TableAdpter 構成ウィザードを利用してアプリを作るのが前提です。

DataGridView に ID と名前を表示

たぶん最初に考え付くのは、TableAdpter 構成ウィザードで、以下のように INNER JOIN した SELECT クエリをベースに型付 DataSet + TableAdapter を作ることではないでしょうか?

SELECT Products.ProductID, Products.ProductName, 
       Products.CategoryID, Categories.CategoryName,
       Products.UnitPrice, Products.Discontinued
FROM   Products INNER JOIN Categories 
ON     Products.CategoryID = Categories.CategoryID

しかしながら、テーブルを JOIN した SELECT クエリをベースに TableAdapter を自動生成させると UPDATE, DELETE, INSERT に必要なコードは一切自動生成されません。

表示するだけではなく、Products テーブルは更新する必要があるという場合、以下のように TableAdpter 構成ウィザードのクエリビルダで、単一の Products テーブルを対象とする SELECT クエリをベースに TableAdapter を生成すれば、Products テーブルを更新するのに必要なメソッドを自動生成してくれます。

クエリビルダ

上の画像の SELECT クエリは以下の通りです。CategoryName を抽出する部分はクエリビルダは自動的には作ってくれませんので、自力で書く必要があります。

SELECT ProductID, ProductName, CategoryID,
       (SELECT CategoryName FROM Categories
        WHERE (Products.CategoryID = CategoryID))
       AS CategoryName,
       UnitPrice, Discontinued
FROM   Products

型付 DataSet + TableAdapter が完成したら、データソースウィンドウを開くとその中に Products という項目があるはずなので、それを Form にドラッグ&ドロップするだけで、DataGridView 上で Products テーブルの表示、編集、更新ができるアプリが完成するはずです。

DataDridView の CategoryName 列の dataGridViewTextBoxColumn は Visual Studio が自動的に ReadOnly = true に設定して生成してくれます(ユーザー入力はできないようになります)。

なお、上記は Products テーブルのみ更新をできればよいというケースですので注意してください。Products テーブルと Categories テーブルの両方を同時に更新したい場合は TableAdapterManager で紹介したように階層更新が可能な形にする必要があります。

Tags: ,

.NET Framework

DataGridView に ComboBox を表示

by WebSurfer 2014年1月23日 15:26

DataGridView の特定の列を ComboBox を使って表示する方法を備忘録として書いておきます。

DataGridView に ComboBox を表示

Northwind サンプルデータベースの Products テーブルを例に使い、上の画像のように Category 列と Supplier 列を ComboBox を使って表示します。

Products テーブルを DataGridView に表示して更新操作ができるようにするだけなら、自分でコードは一行も書かなくても、Visual Studio のウィザードを使ってドラッグ&ドロップ操作だけで Windows Form アプリを作成できます。

ただし、Products テーブルの中の CategoryID, SupplierID は ID(数字)で表示されるので、そのままではユーザーにとっては分かりにくいです。

ID に代えて、名前を Categories, Suppliers テーブルから取得して表示した方がユーザーにとっては分かりやすいはずです。

さらにユーザーがデーターベースを編集・更新する場合は、ComboBox を使用してドロップダウン形式で一覧を表示し、その中からユーザーが選択できるようにするとさらにユーザーフレンドリーになると思います。

今回の例では、CategoryID, SupplierID 列に ComboBox を使い、各行の CategoryID, SupplierID に該当する名前(CategoryName, CompanyName)を Categories, Suppliers テーブルから取得して ComboBox に表示するようにします。

Category 列の方は Visual Studio のウィザードを利用して、自力では一行もコードを書かずに ComboBox を実装してみます。

Supplier 列の方は自力でコードを書いて DataTable を作成し、それを ComboBox の DataSource に設定することにします。

以下にその手順を書きます。

  1. Visual Studio の[ファイル(F)]⇒[新しいプロジェクト(P)...]メニューから[Windows フォームアプリケーション]テンプレートを使って空のプロジェクトを作成する。
  2. ソリューションエクスプローラーでプロジェクトのルートを右クリック。[追加(D)]⇒[新しい項目(W)...]⇒[データセット]で適当な名前(例えば NorthwindDataSet.xsd)をつけて空の xsd ファイルを作成。(注:下の画像はステップ 12 まで進んだ時の完成済みのデータセットで、このステップの時点では何も表示されていません)

NorthwindDataSet.xsd ファイル

  1. ツールボックスから TableAdapter をドラッグ&ドロップすると TableAdapter 構成ウィザードが立ち上がる。
  2. クエリビルダで以下の SELECT クエリを作り、これをベースに DataTable + TableAdapter を作る。

    SELECT ProductID, ProductName, CategoryID, SupplierID,
    UnitPrice, Discontinued FROM Products

    DataGridView に表示するとともに編集・更新操作を行うのはこれなので、TableAdapter 内に作成する更新系のメソッド等の生成オプションはフルにチェックを入れておく。
  3. TableAdapter 構成ウィザードでの操作が完了すると、ProductsDataTable と ProductsTableAdapter が自動生成されているはず。(上の NorthwindDataSet.xsd ファイルの画像で、左側の箱)
  4. Form1.cs を開きそのデザイン画面を表示する。データソースウィンドウを開くとその中に Products という項目があるはずなので、それを Form にドラッグ&ドロップする。
  5. 上のステップまでで、Products テーブルの表示、編集、更新ができるアプリが完成するはず。とりあえずこの段階で DataGridView への表示、レコードの INSERT, DELETE, UPDATE が問題なくできることを確認しておく。
  6. 上記が確認できたら、最初に Category の方を ComboBox で表示するための設定を行う。
  7. 自力でコードを書くのは必要最小限にするため、TableAdapter 構成ウィザードを利用して DataTable + TableAdapter を作り、これを利用する。
  8. NorthwindDataSet.xsd ファイルを開き、ツールボックスからもう一つ TableAdapter をドラッグ&ドロップする。
  9. TableAdapter 構成ウィザードが立ち上がるので、クエリビルダで以下の SELECT クエリを作り、これをベースに DataTable + TableAdapter を作成する。

    SELECT CategoryID, CategoryName FROM Categories

    こちらは、CategoryID に該当する CategoryName を ComboBox を使って表示するためのデーターソースとして利用するだけなので、TableAdapter に更新系のメソッドは不要。
  10. TableAdapter 構成ウィザードでの操作が完了すると、CategoriesDataTable と CategoriesTableAdapter が自動生成されているはず。(上の NorthwindDataSet.xsd ファイルの画像で、右側の箱)
  11. DataGridView の列の編集画面で、CatrgoryID 列の ColumnType を DataGridViewComboBoxColumn に変更する。

列の編集画面その1

  1. 上の画面で、DataSource を[他のデータソース]⇒[プロジェクトデータソース]⇒[NorthwindDataSet]⇒[Catrgories]に設定すると、自動的に categoriesBindingSource が生成され、DataSource に設定される。
  2. 次に、DisplayMember を CategoryName に、ValueMember を CategoryID に設定する。

列の編集画面その2

  1. ここまでの操作で、Category の方は ComboBox で表示され、編集する際は ComboBox をドロップダウンしてその中から選択して更新をかけることが可能になるはず。
  2. 次に、Supplier の方を ComboBox に表示するための設定を行う。こちらは TableAdapter 構成ウィザードを使用しないで、自力でコードを書いて DataTable を作り、それをデーターソースに利用してみる。
  3. Category の場合と同様に、DataGridView の列の編集画面で、SupplierID 列の ColumnType を DataGridViewComboBoxColumn に変更する。
  4. その先は自力でコードを書いて DataTable を作成し、それを DataGridViewComboBoxColumn の DataSource に設定する。
  5. Form1.cs のコード画面を開く。
  6. ADO.NET のライブラリを使い、Suppliers テーブルから SupplierID, CompanyName を取得し DataTable を作成するコードを追加する。具体例は以下のサンプルコードの CreateSuppliersTable を参照。
  7. Form1_Load メソッド(自動生成されているはず)の中に、上記 18 の手順で作成した DataGridViewComboBoxColumn の DataSource プロパティを CreateSuppliersTable メソッドが返す DataTable に、DisplayMember プロパティを "CompanyName" に、ValueMember プロパティを "SupplierID" に設定する。具体例は以下のサンプルコードを参照。
  8. 以上の操作で、一番上の画像のアプリが完成するはずです。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;  // 要追加

namespace DataGridViewComboBox
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void productsBindingNavigatorSaveItem_Click(
        object sender, EventArgs e)
    {
      this.Validate();
      this.productsBindingSource.EndEdit();
      this.tableAdapterManager.UpdateAll(
          this.northwindDataSet);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      this.categoriesTableAdapter.Fill(
          this.northwindDataSet1.Categories);
      this.productsTableAdapter.Fill(
          this.northwindDataSet.Products);
      // ここまでのコードは Visual Studio のウィザードで
      // 自動生成される。


      // ここから下のコードを自力で書いて追加する。

      // DataSource に設定するのは Supplier の ComboBox に
      // 表示するデータを含む DataTable。下のヘルパーメソッ
      // ド CreateSuppliersTable で作成。
      this.dataGridViewTextBoxColumn4.DataSource = 
          CreateSuppliersTable();
      this.dataGridViewTextBoxColumn4.DisplayMember = 
          "CompanyName";
      this.dataGridViewTextBoxColumn4.ValueMember = 
          "SupplierID";
    }

    // Suppliers テーブルから SupplierID, CompanyName を抽出
    // して DataTable を作るためのヘルパーメソッド。
    private DataTable CreateSuppliersTable()
    {
      DataTable table = new DataTable("Suppliers");
      table.Columns.Add(
            new DataColumn("SupplierID", typeof(int)));
      table.Columns.Add(
            new DataColumn("CompanyName", typeof(string)));

      string connString = DataGridViewComboBox.Properties.
          Settings.Default.NORTHWNDConnectionString;
      string query = 
          "SELECT SupplierID, CompanyName FROM Suppliers " + 
          "ORDER BY SupplierID";

      using (SqlConnection conn = new SqlConnection(connString))
      {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(query, conn))
        {
          using (SqlDataReader reader = cmd.ExecuteReader())
          {
            if (reader != null)
            {
              while (reader.Read())
              {
                DataRow row = table.NewRow();
                row["SupplierID"] = reader.GetInt32(0);
                row["CompanyName"] = reader.GetString(1);
                table.Rows.Add(row);
              }
            }
          }
        }
      }
      return table;
    }

  }
}

Tags: , ,

.NET Framework

TableAdapter と Transaction

by WebSurfer 2011年12月18日 20:33

Visual Studio を利用してウィザードベースで自動生成する型付 DataSet + TableAdapter を使ってデータベースを更新する際、手動トランザクション処理するにはどうしたらいいでしょうか?(MS-DTC を使う自動トランザクションではなくて)

Visual Studio 2008 から TableAdapter に Transaction プロパティが追加されたので、それと、それ以前からある Connection プロパティを使えば、Visual Studio 2005 以前と比較して手動トランザクションが容易に設定できます。

でも、Visual Studio 2008 以降を使っているなら、そもそも手動トランザクションをかけるコードを自力で書く必要はなくて、自動生成される TableAdapterManager クラスの UpdateAll メソッドを使用すればいいです。

実は知らなかったのですが、TableAdapterManager.UpdateAll メソッドのコードをよく見てみると、そのメソッドの中でトランザクションがかかるようになってました。

もともと、TableAdapterManagerは 階層更新 を実現する ため(即ち、複数のテーブルを、データベース内の制約によって定義される一貫性規則を守って関連レコードの挿入、更新、および削除を制御するため)のものということらしいですが、単一テーブルの場合もトランザクションは有効に働きます。

という訳で、Visual Studio 2008 以降なら TableAdapterManager の UpdateAll メソッドを使うのが正解だと思います。

ちなみに、Visual Studio 2005 以前の場合は Transaction プロパティは自動生成されたコードには定義されません。TableAdapter は partial クラスとして定義されているので、自動生成されたファイルとは別に、Visual Studio 2008 以降で生成されるコードを参考に、自力で Transaction プロパティを定義して使うのがいいと思います。SqlClient の場合は以下のような感じです。

private System.Data.SqlClient.SqlTransaction _transaction;

internal System.Data.SqlClient.SqlTransaction Transaction {
  get {
    return this._transaction;
  }
  set {
    this._transaction = value;
    for (int i = 0; i < this.CommandCollection.Length; i++) {
      this.CommandCollection[i].Transaction = this._transaction;
    }
    if (((this.Adapter != null) 
        && (this.Adapter.DeleteCommand != null))) {
      this.Adapter.DeleteCommand.Transaction = this._transaction;
    }
    if (((this.Adapter != null) 
        && (this.Adapter.InsertCommand != null))) {
      this.Adapter.InsertCommand.Transaction = this._transaction;
    }
    if (((this.Adapter != null) 
        && (this.Adapter.UpdateCommand != null))) {
      this.Adapter.UpdateCommand.Transaction = this._transaction;
    }
  }
}

どうも、Visual Studio 2008 から TableAdapter に Transaction プロパティが追加された理由は、TableAdapterManager.UpdateAll メソッドで手動トランザクションをかけるためのようです。

Tags: ,

ADO.NET

About this blog

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

Calendar

<<  2017年4月  >>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

View posts in large calendar