前回は「データベースとSQL」の基礎をやりました。

今回は、いよいよ実践。C#のプログラムから、データベースに接続して操作する方法です。業務系開発の、まさに中心になる部分です。

C#からデータベースを使うには、「つなぐ → SQLを送る → 結果を受け取る → 閉じる」という流れをたどります。

全体の流れをつかむ

細かい文法に入る前に、流れを頭に入れましょう。C#からデータベースを使うときは、いつもこの4ステップです。

  1. つなぐ … データベースへの接続を開く
  2. SQLを送る … 「これを取って」「これを保存して」とお願いする
  3. 結果を受け取る … 取り出したデータを、C#で受け取る
  4. 閉じる … 接続を閉じる

電話に似ています。電話をかけて(つなぐ)、用件を伝えて(SQL)、返事を聞いて(結果)、電話を切る(閉じる)。この流れは、どんな操作でも同じです。

つなぐ ── 接続文字列

まず、データベースに「つなぐ」ところから。つなぐには、接続文字列という、接続先の情報が必要です。

string connectionString =
    "Server=localhost;Database=店舗管理;Trusted_Connection=True;";

これは「どのサーバーの、どのデータベースに、どうつなぐか」を書いた文字列です。SQL Server の場合の一例です。

  • Server=... … データベースがある場所
  • Database=... … つなぐデータベースの名前

この文字列の中身は、使うデータベースや環境によって変わります。今は「接続先を書いたもの」とだけ理解すれば十分です。

データを取り出す(SELECT)

実際に、顧客データを取り出してみます。SQL Server なら、こう書きます。

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();   // ① つなぐ

    var command = new SqlCommand("SELECT 名前, 年齢 FROM 顧客", connection);

    using (var reader = command.ExecuteReader())   // ② SQLを送る
    {
        while (reader.Read())   // ③ 結果を1行ずつ受け取る
        {
            string name = reader["名前"].ToString();
            int age = (int)reader["年齢"];
            Console.WriteLine(name + ":" + age + "歳");
        }
    }
}   // ④ ここで自動的に閉じる

少し長いですが、さっきの4ステップが、そのまま入っています。

  • connection.Open() … ① つなぐ
  • new SqlCommand("SELECT ...") … ② 送るSQLを用意して、実行
  • reader.Read() … ③ 結果を1行ずつ読む(第10回の while ですね)
  • reader["名前"] … その行の「名前」列の値を取り出す

while (reader.Read()) で、取り出した行を1件ずつ処理しています。1行ある限りループし、無くなったら終わる。第10回の while 文が、ここで活きています。

using が、閉じ忘れを防ぐ

ここで、using(ユージング)という新しい書き方が出てきました。

using (var connection = new SqlConnection(connectionString))
{
    // ここで connection を使う
}   // ← ここを抜けると、自動的に閉じられる

using で囲むと、そのカッコを抜けたとき、自動的に接続を閉じてくれます

これは、とても大事です。データベース接続は、使い終わったら必ず閉じる必要があります。閉じ忘れると、接続が無駄に残り続け、やがてデータベースがパンクします。

using を使えば、閉じ忘れの心配がありません。第27回の finally(必ず実行される後片付け)を、もっと安全・簡単にした仕組みだと思ってください。

データを保存する(INSERT)

取り出すだけでなく、保存もできます。

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();

    var command = new SqlCommand(
        "INSERT INTO 顧客 (名前, 年齢) VALUES (@name, @age)", connection);

    command.Parameters.AddWithValue("@name", "鈴木");
    command.Parameters.AddWithValue("@age", 40);

    command.ExecuteNonQuery();   // 取り出さない操作は ExecuteNonQuery
}

ここで、ひとつ大事な書き方が出てきます。@name@age というパラメータです。

SQLの中に値を直接書かず、@name という「空欄」にしておいて、後から AddWithValue で値を入れる。一見、回りくどいですよね。でも、これにはとても重要な理由があります。

なぜパラメータを使うのか ── 現場の鉄則

値を直接SQLに埋め込むと、こう書けてしまいます。

// 悪い例:絶対にやってはいけない
string name = Console.ReadLine();
var command = new SqlCommand("INSERT INTO 顧客 (名前) VALUES ('" + name + "')", ...);

これは、やってはいけない書き方です。

ユーザーが入力した文字を、そのままSQLに埋め込むと、悪意のある入力でデータベースを壊されたり、情報を盗まれたりする危険があります。これを「SQLインジェクション」という攻撃と呼びます。

@name のパラメータを使えば、入力された値は「ただのデータ」として安全に扱われ、この攻撃を防げます。

これは、業務系開発の鉄則です。20年この仕事をしてきて、ここだけは絶対に譲れません。ユーザーの入力をSQLに使うときは、必ずパラメータを使う。文法の便利さの話ではなく、システムを守るための作法です。

つまずきポイント

初心者がやりがちなのが、さっきの「値を直接埋め込む」書き方です。

動いてしまうので、つい楽な方を選びがちです。でも、それは危険な穴を開けることになります。

SQLに値を入れるときは、パラメータ(@○○)を使う」。最初から、これを習慣にしてください。後から直すのは大変ですが、最初から正しく書けば、何も難しくありません。

まとめ

C#からデータベースを使う流れは、つなぐ → SQLを送る → 結果を受け取る → 閉じる。

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();
    var command = new SqlCommand("SELECT ...", connection);
    // 取り出す or 保存する
}   // using が自動で閉じる
  • 接続は、使い終わったら必ず閉じる(using が安全)
  • 取り出すなら ExecuteReader、保存・更新・削除なら ExecuteNonQuery
  • ユーザーの入力は、必ずパラメータ(@○○)で渡す(鉄則)

次回は、データベースの「表」と、C#の「クラス」を対応させる考え方を見ていきます。