更新日: 2009 年 12 月 11 日

Visual Basic の内容はこちらに掲載しています。10 行でズバリ !! 言語統合型のデータ クエリ技術 (LINQ) (VB)

このコンテンツのポイント

  • Visual Studio における LINQ to SQL の利用方法
  • LINQ to SQL によるクエリの記述方法

今回紹介するコード

C#
using System;
using System.Linq;

using System.Data.Linq;

namespace LINQConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthWindDataContext dc = new NorthWindDataContext();
            Table<Customers> customerTable = dc.Customers;

            dc.Log = Console.Out; // ログも画面に出力

            var customers = from n in customerTable
                            where n.Orders.Count() >= 20
                            select n;

            foreach (var c in customers)
            {
                Console.WriteLine("{0} : {1}", c.CustomerID, c.CompanyName);
            }

            Console.ReadLine(); // 一時停止用
        }
    }
}
 

目次

  1. はじめに
  2. サンプル アプリケーションの開発準備
  3. データベースの準備
  4. LINQ to SQL クラスの準備
  5. LINQ によるクエリの記述
  6. SQL ステートメントの確認
  7. 2 つのテーブルにまたがるクエリの記述

1. はじめに

.NET アプリケーションからデータベースにアクセスする場合、以下の 2 つが最も基本的な方法です。

  • 個別に SQL ステートメントを送信し、その結果を取得する接続型のアクセス
  • 必要なデータを最初にデータセットへすべて読み込む非接続型のアクセス

ここで解説する「LINQ to SQL」は、これらに続く第 3 のデータベース アクセス方法といえます (ほかには Entity Data Model を使用したアクセス方法もあります。これについては「10 行でズバリ !! 概念モデルを使用したデータ アクセス (Object Services) (C#)」で解説されています)。

LINQ to SQL では、LINQ (Language Integrated Query、言語統合型クエリ) と呼ばれる、SQL ステートメントによく似た C# 言語の構文を使ってクエリ (問い合わせ文) を記述します。このクエリは、LINQ to SQL のフレームワーク (LINQ to SQL のために用意されたクラス ライブラリ) により SQL ステートメントに変換され、データベースに送られます。

ここでは Visual Studio で LINQ to SQL を利用する手順を説明し、データベースを参照する簡単な LINQ のクエリ文を記述して実行してみます。

ページのトップへ


2. サンプル アプリケーションの開発準備

ここではサンプル アプリケーションとしてコンソール アプリケーションを作成します。まずはそのプロジェクトを新規作成しましょう。

Visual Studio を起動して、[ファイル] メニューの [新規作成] から [プロジェクト] をクリックし、[新しいプロジェクト] ダイアログを開きます。そして [プロジェクトの種類] で [Windows] を、[テンプレート] では [コンソール アプリケーション] を選択します。[プロジェクト名] は任意の名前を指定できますが、ここでは「LINQConsoleApplication」としました。

図 1 [新しいプロジェクト] ダイアログでコンソール アプリケーションのプロジェクトを新規作成

ページのトップへ


3. データベースの準備

次に、LINQ to SQL によりアクセスするデータベースの準備を行います。データベースとしては、このページ (英語) からダウンロードできる Northwind データベース (NORTHWND.MDF ファイル) を使用します。

この NORTHWND.MDF ファイルをソリューション エクスプローラーのプロジェクト名部分 (ここでは LINQConsoleApplication) にドラッグ & ドロップしてください。データ ソース構成ウィザードが起動しますが、これは [キャンセル] ボタンをクリックして閉じます。これによりファイルがプロジェクトのフォルダーにコピーされます。

ページのトップへ


4. LINQ to SQL クラスの準備

続いては、LINQ to SQL を利用する準備として、LINQ to SQL クラスをプロジェクトに追加します。

これには、[プロジェクト] メニューの [新しい項目の追加] を選択し、[新しい項目の追加] ダイアログを開きます。そして、[テンプレート] として [LINQ to SQL クラス] を選択します。また、ここではファイル名を「NorthWind」としています。

図 2 [テンプレート] として [LINQ to SQL クラス] を選択して項目を追加

[追加] ボタンをクリックすると、プロジェクトにいくつかの項目が追加され、OR デザイナー (Object Relational Designer) が開きます。

図 3 OR デザイナー (Object Relational Designer)

次に、画面左端のサーバー エクスプローラーを開き、[NORTHWND.MDF] の項目を展開します (この項目がない場合には、ソリューション エクスプローラーで [NORTHWND.MDF] をダブルクリックしてください)。さらに [テーブル] の項目を展開すると、データベース内にあるテーブルの一覧が現れます。今回は例として Customers テーブルと Orders テーブルを使用しますので、この 2 つの項目をそれぞれ、OR デザイナー上にドラッグ & ドロップしてください。

図 4 OR デザイナーで作成した Customers クラスと Orders クラス

OR デザイナー上には、矢印により関連付けられた 2 つのボックスが作成されます。これらのボックスは、データベースの各テーブルの構造をそのまま反映したクラスを表しており、また、矢印はデータベース上でのリレーションを基に作成されたクラス間での参照を表しています。これらのクラスのオブジェクトは、テーブルから取得した 1 つのレコードを表し、レコードの各列の値は、そのプロパティとしてアクセスできます。

実際のクラスの定義は NorthWind.designer.cs に自動的に記述されており、これはソリューション エクスプローラーから開いて確認できます。

図 5 自動生成された Customers クラス、Orders クラス、NorthWindDataContext クラス

このファイルを見ると、「Customers クラス」と「Orders クラス」のほかに、もう 1 つ「NorthWindDataContext クラス」が作成されているのが分かります。このクラスは、データベースのレコードと、前者 2 つのクラスのオブジェクトとの橋渡しを行うクラスであり、LINQ to SQL を使う上で中心的なオブジェクトとなります (「データ コンテキスト」と呼ばれます)。

以上で、LINQ to SQL を使って LINQ によりクエリを実行する準備がすべて整いました。以降では実際にクエリを行う C# のコードを記述していきます。

ページのトップへ


5. LINQ によるクエリの記述

コードはプロジェクト内の Program.cs に記述しますので、これをソリューション エクスプローラーで開き、まずは次のようなコードを記述してみてください。太字の部分が手で入力するコードです。

using System;
using System.Linq;

using System.Data.Linq;

namespace LINQConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthWindDataContext dc = new NorthWindDataContext();
            Table<Customers> customerTable = dc.Customers;

            var customers = from n in customerTable
                                      where n.Country == "France"
                                      select n;

            foreach (var c in customers)
            {
                Console.WriteLine("{0} : {1}", c.CustomerID, c.CompanyName);
            }

            Console.ReadLine(); // 一時停止用
        }
    }
}

このコードは Customers テーブルにアクセスし、Country 列の値が「France」のレコードを取得し、そのレコードの CustomerID 列と CompanyName 列の値を表示します。

Visual Studio で [F5] キーを押してアプリケーションを実行すると、実行結果は次の画面のようになります。

図 6 Country 列の値が「France」のレコードを表示

それでは順にコードを説明していきます。

まずデータ コンテキスト クラスをインスタンス化し、その Customers プロパティから、以降で行うクエリの対象となるテーブル オブジェクトを取り出します。このテーブル オブジェクトは、先ほど OR デザイナーでドラッグ & ドロップにより作成した Customers クラスに基づき作成されるクエリ用のオブジェクトで、Customers オブジェクトのコレクションを表します。

C#
NorthWindDataContext dc = new NorthWindDataContext();
Table<Customers> customerTable = dc.Customers;
 

そして、コードの中央付近にある、次の 3 行が LINQ によるクエリです。

C#
var customers = from n in customerTable
                where n.Country == "France"
                select n;
 

これは、

  • Customers テーブルから順に 1 レコードを取り出して変数 n に代入し (from n in customerTable)
  • その Country 列の値が「France」であれば (where n.Country == "France")
  • それを抽出する (select n)

という意味のクエリです。LINQ によるクエリは、このような、

from 変数 in テーブル where 抽出条件 select 抽出対象

が基本的な記述形式です。ここでは説明を割愛しますが、join や orderby、group といった句も利用できます。

使用されている「from」や「in」などのキーワードは C# のキーワードであり、クエリがダブルクォーテーションで囲んだ文字列ではないという点がポイントです。このため Visual Studio 上で IntelliSense を使いながらクエリを記述でき、コンパイル時にクエリの記述ミスを発見することもできます。

そして、結果を格納している変数 customers は、このようにして抽出された Customers オブジェクトのコレクションとなります。このコレクションに対しては、foreach ステートメントを使用して、個々のデータにアクセスします。

C#
foreach (var c in customers)
{
    Console.WriteLine("{0} : {1}", c.CustomerID, c.CompanyName);
}
 

なお、LINQ to SQL においては、実はこのときに初めて SQL ステートメントがデータベースに対して発行されます。このような遅延評価により、データベースへのアクセスは最小限に抑えられています。

ページのトップへ


6. SQL ステートメントの確認

それでは、上記のようなクエリから実際にはどのような SQL ステートメントが生成されるのでしょうか。これはクエリ部分の直前に、次のような 1 行 (太字の行) を追加して確認できます。

        NorthWindDataContext dc = new NorthWindDataContext();
        Table<Customers> customerTable = dc.Customers;

        dc.Log = Console.Out; // ログを画面に出力

        var customers = from n in customerTable
                                  where n.Country == "France"
                                  select n;

この状態でアプリケーションを実行すると、実行結果は次の画面のようになります。画面の最初の 5 行が実際にデータベースに対して発行された SQL ステートメントです。

図 7 クエリから生成される SQL ステートメントを表示

ページのトップへ


7. 2 つのテーブルにまたがるクエリ

最後に、別のクエリの記述例として、2 つのテーブルにまたがるクエリを記述してみましょう。次のコードでは、20 件以上の注文データを持つ顧客データを抽出して表示しています。

C#
using System;
using System.Linq;

using System.Data.Linq;

namespace LINQConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthWindDataContext dc = new NorthWindDataContext();
            Table<Customers> customerTable = dc.Customers;

            dc.Log = Console.Out; // ログも画面に出力

            var customers = from n in customerTable
                            where n.Orders.Count() >= 20
                            select n;

            foreach (var c in customers)
            {
                Console.WriteLine("{0} : {1}", c.CustomerID, c.CompanyName);
            }

            Console.ReadLine(); // 一時停止用
        }
    }
}
 

データベース上のリレーションシップに従って、Customers クラスには、関連する Orders オブジェクトを参照するための Orders プロパティが自動で作成されています。これを利用することにより、クエリはこのように非常に簡潔に記述できます。

このコードの実行結果は次の画面のようになります。

図 8 2 つのテーブルにまたがるクエリの実行結果

LINQ のクエリは、副問い合わせを使用した SQL ステートメントに変換されており、期待したとおりといえます。


Code Recipe

ページのトップへ