Entity Frameworkを利用してレコードを検索する - C#

Entity Frameworkを利用してレコードを検索するコードを紹介します。

プログラム例

テーブル

データベースに下記のテーブルを作成します。
ProductAテーブル レコード
idnamepricecategory
1Penguin500Bird
2Bear1050Mammal
3Duck150Bird
4Camel550Mammal
5Owl185Bird
6Whale880Mammal

データモデルの作成

こちらの記事を参照して、CodeFirst形式でデータモデルを作成します。

UI

Windowsフォームを作成し、下図のUIを作成します。複数行のテキストボックスとボタンを配置します。

コード

下記のコードを作成します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EntityFrameworkDBOperationDemo
{
  public partial class FormSelect : Form
  {
    public FormSelect()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      ModelProductsA model = new ModelProductsA();

      foreach (ProductsA i in model.ProductsA) {
        textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
      }
    }

    private void button2_Click(object sender, EventArgs e)
    {
      ModelProductsA model = new ModelProductsA();

      IQueryable<ProductsA> query = from product in model.ProductsA select product;

      foreach (ProductsA i in model.ProductsA) {
        textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
      }
    }

    private void button3_Click(object sender, EventArgs e)
    {
      ModelProductsA model = new ModelProductsA();

      foreach (ProductsA i in model.ProductsA.Where(item => item.price < 500)) {
        textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
      }
    }

    private void button4_Click(object sender, EventArgs e)
    {
      ModelProductsA model = new ModelProductsA();

      IQueryable<ProductsA> query = from product in model.ProductsA
                                    where product.price < 500
                                    select product;

      foreach (ProductsA i in query) {
        textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
      }
    }


    private void button5_Click(object sender, EventArgs e)
    {
      ModelProductsA model = new ModelProductsA();

      foreach (ProductsA i in model.ProductsA.Where(WhereProc)) {
        textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
      }
    }


    private bool WhereProc(ProductsA item)
    {
      if (item.price < 500) {
        return true;
      }
      else {
        return false;
      }
    }
  }
}

解説

button1, button2 がすべてのレコードを取得するコードになります。button3, button4, button5 が条件に一致するレコードを取得するコードです。

button1

ProductsAテーブルのモデルオブジェクトModelProductsA を作成します。作成後、foreach文でレコードにアクセスします。foreach文内で model.ProductsA を与えるとすべてのレコードをが含まれるDbSet<ProductsA> が取得できます。
private void button1_Click(object sender, EventArgs e)
{
  ModelProductsA model = new ModelProductsA();

  foreach (ProductsA i in model.ProductsA) {
    textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
  }
}

button2

button2はbutton1と同様の動作となりますが、foreach文のin の指定がbutton2ではクエリ形式のLINQを与えています。
private void button2_Click(object sender, EventArgs e)
{
  ModelProductsA model = new ModelProductsA();

  IQueryable<ProductsA> query = from product in model.ProductsA select product;

  foreach (ProductsA i in query) {
    textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
  }
}

button3

button3では、条件に一致したレコードを取得する動作になります。`ModelProductsA'オブジェクトの作成までは同様です、foreach文dでinの後ろに model.ProductsA.Where メソッドを呼び出した結果を与えています。Whereメソッドの引数には式形式のLINQを与え、priceの値が500以下の要素のみを抽出しています。
private void button3_Click(object sender, EventArgs e)
{
  ModelProductsA model = new ModelProductsA();

  foreach (ProductsA i in model.ProductsA.Where(item => item.price < 500)) {
    textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
  }
}

button4

button4はbutton3と同様の処理のコードですが、foreach文のinにはクエリ形式のLINQを与えています。
private void button4_Click(object sender, EventArgs e)
{
  ModelProductsA model = new ModelProductsA();

  IQueryable<ProductsA> query = from product in model.ProductsA
                                where product.price < 500
                                select product;

  foreach (ProductsA i in query) {
    textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
  }
}

button5

button5はbutton3, button4 と同じ動作ですが、Whereメソッドに与える引数をメソッド名に設定しています。
private void button5_Click(object sender, EventArgs e)
{
  ModelProductsA model = new ModelProductsA();

  foreach (ProductsA i in model.ProductsA.Where(WhereProc)) {
    textBox1.Text += string.Format("{0:d}\t{1}\t{2:g}\r\n", i.id, i.name.Trim(), i.price);
  }
}


private bool WhereProc(ProductsA item)
{
  if (item.price < 500) {
    return true;
  }
  else {
    return false;
  }
}

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。下図の結果がテキストボックスに表示されます。すべてのレコードが取得できたことが確認できます。


[button2]をクリックします。下図の画面が表示されます。こちらも、すべてのレコードが取得でき、テキストボックスに表示されていることが確認できます。


[button3]をクリックします。priceの値が150以下のレコードが取得できています。


[button4]をクリックします。[button3]クリック時と同様の結果が表示されます。


[button5]をクリックします。[button3][button4]クリック時と同様の結果が表示されます。

補足: LINQの検索条件がSQL文に反映されているのか?

foreach文内のLINQやWhereメソッド内のLINQで指定した条件式が、データベースのクエリに反映されているのか、データベースクエリには反映されず、すべてのレコードを取得した後で条件判定しているだけなのかは気になる部分です。
上記のアプリケーションで[button3],[button4]クリック時のデータベースのセッションを確認し、実行されたクエリを確認したところ下図でした。


LINQで指定した条件式はSQLの条件式にも反映されており、すべてのレコードを取得した後に条件判定する動作ではないことがわかります。
SELECT 
    [Extent1].[id] AS [id], 
    [Extent1].[name] AS [name], 
    [Extent1].[price] AS [price], 
    [Extent1].[category] AS [category]
    FROM [dbo].[ProductsA] AS [Extent1]
    WHERE [Extent1].[price] < cast(500 as decimal(18))

一方、[button5]をクリックした場合は、下記のSQLが実行されていることが確認できました。LINQでないメソッドがWhereメソッドに与えられた場合は、SQL文には反映されず、レコード取得後に処理により結果から除外されているようです。


SELECT 
    [Extent1].[id] AS [id], 
    [Extent1].[name] AS [name], 
    [Extent1].[price] AS [price], 
    [Extent1].[category] AS [category]
    FROM [dbo].[ProductsA] AS [Extent1]

SQL Server でセッションで実行されているクエリを調べる手順はこちらの記事を参照してください。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2024-01-07
作成日: 2019-01-23
iPentec all rights reserverd.