C#入門㉟ 表とクラスを対応させる ── データを「もの」として扱う
前回は「C#からデータベースに接続する」をやりました。
今回は、業務系開発の設計でとても大事な考え方。データベースの「表」と、C#の「クラス」を対応させるという発想です。これが分かると、プログラムがぐっと整理されます。
表の1行を、クラスの1インスタンスに対応させる。これが、データを扱う基本の設計です。
バラバラのデータは、扱いにくい
前回、データベースから顧客を取り出すとき、こう書きました。
while (reader.Read())
{
string name = reader["名前"].ToString();
int age = (int)reader["年齢"];
Console.WriteLine(name + ":" + age + "歳");
}
名前は name、年齢は age と、バラバラの変数で受け取っています。1人分なら、これでもいいです。
でも、この顧客データを、別のメソッドに渡したいときは? 計算に使いたいときは? 名前と年齢を、いちいち2つ別々に持ち回ることになります。第18回でやった「バラバラの変数は扱いにくい」という、あの問題が、また出てきます。
表の構造は、クラスとそっくり
ここで、前々回(第33回)の表を、もう一度見てみましょう。
顧客テーブル
┌──────┬────────┬─────┐
│ ID │ 名前 │ 年齢 │
├──────┼────────┼─────┤
│ 1 │ 山田 │ 20 │
└──────┴────────┴─────┘
「ID・名前・年齢を持つ」。この構造、第18回で作ったクラスと、そっくりですよね。
だったら、表に対応するクラスを作ればいいんです。
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
「顧客テーブル」に対応する「Customer クラス」。表の列が、クラスのプロパティに対応します。
- 表の
ID列 → クラスのIdプロパティ - 表の
名前列 → クラスのNameプロパティ - 表の
年齢列 → クラスのAgeプロパティ
表の1行を、1インスタンスにする
そして、表の1行を、クラスの1インスタンスとして受け取ります。
List<Customer> customers = new List<Customer>();
while (reader.Read())
{
Customer customer = new Customer(); // 1行 = 1インスタンス
customer.Id = (int)reader["ID"];
customer.Name = reader["名前"].ToString();
customer.Age = (int)reader["年齢"];
customers.Add(customer); // リストにためる
}
表の1行を読むたびに、Customer のインスタンスを1つ作って、データを詰める。そして、List にためていく。
これで、データベースの顧客データが、C#の「もの(オブジェクト)」の一覧になりました。バラバラの変数ではなく、「顧客」という意味のあるまとまりです。
まとまっていると、何が嬉しいか
クラスにまとめると、その後の扱いが、劇的にラクになります。
第29回でやったLINQが、そのまま使えます。
// 30歳以上の顧客の名前を取り出す
var names = customers
.Where(c => c.Age >= 30)
.Select(c => c.Name);
メソッドに渡すのも、一言です。
SendMail(customer); // 顧客まるごと、1つで渡せる
バラバラの変数なら SendMail(name, age, id, ...) と全部渡す必要がありますが、クラスにまとめてあれば、customer 1つで済みます。
「データを、意味のあるまとまり(もの)として扱う」。これが、オブジェクト指向と、データベースが出会うところです。連載でやってきたクラス(第18回〜)と、データベース(第33回〜)が、ここで1つにつながります。
この対応づけには、名前がある
「表とクラスを対応させる」この作業は、実務でとても頻繁にやります。あまりに頻繁なので、それを自動でやってくれる道具まであります。
「ORM(オーアールエム)」と呼ばれる仕組みです。C#では「Entity Framework」が有名です。ORMを使うと、前回書いたような接続やSQLの多くを、自分で書かずに済みます。
// ORM を使うと、こんなイメージで書ける
var customers = db.Customers.Where(c => c.Age >= 30).ToList();
SQLを書かずに、LINQのような書き方で、データベースを操作できる。表とクラスの対応も、自動でやってくれます。
ただ、最初は自動の道具に頼らず、前回のように手で書いてみるのがおすすめです。中で何が起きているかを知っていると、ORMを使うときも、問題が起きたときに対応できます。「裏で何が動いているか」を知る人は、強いです。
つまずきポイント
初心者が見落としがちなのが、「なぜ、わざわざクラスにするのか」という点です。
「reader["名前"] で直接取れるのに、なぜCustomerクラスを作るの?」と。
理由は、プログラムが大きくなったときに効いてくるからです。小さなプログラムなら、バラバラの変数でも動きます。でも、顧客データをあちこちで使い回す本格的なシステムでは、「顧客」という意味のまとまりがあるかどうかで、コードの整理しやすさがまったく変わります。
「データに、意味のある形を与える」。これは、長く保守できるプログラムを書くための、大事な習慣です。
まとめ
データベースの表と、C#のクラスを対応させるのが、データ設計の基本。
class Customer // 表に対応するクラス
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
// 表の1行を、1インスタンスにして、List にためる
- 表の列 → クラスのプロパティ、表の1行 → 1インスタンス
- まとめると、LINQやメソッドで扱いやすくなる
- この対応を自動化する道具が「ORM」(Entity Framework など)
- 最初は手で書いて、中の仕組みを知っておくとよい
クラス・継承・データベース——連載でやってきたことが、業務系開発の現場で、こうやって1つにつながっていきます。

