このヘージと関連するページ一覧

  • LINQ - Select
  • LINQ - GroupBy
  • LINQ - Join

  • このページの最終更新日 2020/10/25

    [C#] LINQ - Select

    1. Where句について

     データベースで社員番号、社員名、名前を管理して必要なデータを取得したいとします。SQLiteでは、
    CREATE TABLE Employee(EmployeeId int, EmployeeName text, Age int)
    などとテーブルを作成し、
    INSERT INTO Employee(EmployeeId, EmployeeName, Age) VALUES(1,'鈴木',24)
    INSERT INTO Employee(EmployeeId, EmployeeName, Age) VALUES(1,'佐藤',25)
    INSERT INTO Employee(EmployeeId, EmployeeName, Age) VALUES(1,'田中',26)
    とデータを挿入して、例えば社員番号2の社員のデータを取得したいとすると、
    SELECT EmployeeId,EmployeeName,Age WHERE EmployeeId = 2
    のようにSQL文を発行するとデータを取得することが出来ます。

     これと同じようなことをLINQを使って実装することを考えます。まずデータベースのテーブルをクラス(Employee)として定義し、テーブルの列に相当するものはpublic なプロパティとして定義します。
    データベースの例と同様に、社員番号が2の社員を取得する場合は、

    - code.1 -
    public class Employee
    {
        public int EmployeeId { get; set; }
        public string EmployeeName { get; set; }
        public int Age { get; set; }
    
        public override string ToString()
        {
            return string.Format("社員番号={0}, 氏名={1}, 年齢={2}", this.EmployeeId, this.EmployeeName, this.Age);
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var employeeList = new List<Employee>();
            employeeList.Add(new Employee() { EmployeeId = 1, EmployeeName = "鈴木", Age = 24 });
            employeeList.Add(new Employee() { EmployeeId = 2, EmployeeName = "佐藤", Age = 25 });
            employeeList.Add(new Employee() { EmployeeId = 3, EmployeeName = "田中", Age = 26 });
    
            Employee employeeId2 = employeeList.Where(m => m.EmployeeId == 2).Single();
            Console.WriteLine(employeeId2); //社員番号=2, 氏名=佐藤, 年齢=25
        }
    }

     と、code.1のように書けます。Singleは条件を満たす要素が1つでなければエラーを投げます。例えばcode.2のように条件を満たす要素が何もない場合は、「シーケンスに要素が含まれていません」というメッセージエラーが表示されます。複数条件を満たすものがある場合は、「シーケンスに複数の要素が含まれています」というエラーメッセージが返されます。

    - code.2 -
    static void Main(string[] args)
    {
        try
        {
            var employeeList = new List<Employee>();
            employeeList.Add(new Employee() { EmployeeId = 1, EmployeeName = "鈴木", Age = 24 });
            employeeList.Add(new Employee() { EmployeeId = 2, EmployeeName = "佐藤", Age = 25 });
            employeeList.Add(new Employee() { EmployeeId = 3, EmployeeName = "田中", Age = 26 });
    
            Employee employeeId4 = employeeList.Where(m => m.EmployeeId == 4).Single();
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message); //シーケンスに要素が含まれていません
        }
    }

     おわかりだとは思いますが、Singleメソッドは要素のうち条件を満たすものが1つであると期待され、そうでない場合は異常であると見なされるような場合に基本的に使用するメソッドです。条件を満たすものが1つだけであるか、もしくは存在しないことが想定され、これらによって条件を分岐したい場合などはcode.3のようにSingleOrDefaultメソッドを使用します。

    - code.3 -
    static void Main(string[] args)
    {
        try
        {
            var employeeList = new List<Employee>();
            employeeList.Add(new Employee() { EmployeeId = 1, EmployeeName = "鈴木", Age = 24 });
            employeeList.Add(new Employee() { EmployeeId = 2, EmployeeName = "佐藤", Age = 25 });
            employeeList.Add(new Employee() { EmployeeId = 3, EmployeeName = "田中", Age = 26 });
    
            Employee employeeId4 = employeeList.Where(m => m.EmployeeId == 4).SingleOrDefault();
    
            if (employeeId4 != null)
            {
                Console.WriteLine(employeeId4);
            }
            else
            {
                Console.WriteLine("社員番号4の社員は存在しません。"); //社員番号4の社員は存在しません。
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

     複数の要素を列挙したい場合は、例えば以下のように書けます。code.4は3人居る社員のなかから25歳以上の人を列挙するコードです。Where(m => m.Age >= 25) が実行された時点で返却されるオブジェクトはIEnumerable<Employee>オブジェクトです。
     「IEnumerable」というのはあまり聞きなれない人も居るかもしれませんが、.NETの世界では配列もIEnumerableインターフェースを実装しておりLINQを学ぶ上でも非常に重要です。Microsoftの解説ページのリンク 「https://msdn.microsoft.com/ja-jp/library/9eekhta0(v=vs.110).aspx」も貼っておきますので目を通して頂きたく。

    - code.4 -
    static void Main(string[] args)
    {
        var employeeList = new List<Employee>();
        employeeList.Add(new Employee() { EmployeeId = 1, EmployeeName = "鈴木", Age = 24 });
        employeeList.Add(new Employee() { EmployeeId = 2, EmployeeName = "佐藤", Age = 25 });
        employeeList.Add(new Employee() { EmployeeId = 3, EmployeeName = "田中", Age = 26 });
    
        List<Employee> employeeOlderOrEqual25 = employeeList.Where(m => m.Age >= 25).ToList();
        employeeOlderOrEqual25.ForEach(m => Console.WriteLine(m)); //社員番号=2, 氏名=佐藤, 年齢=25
                                                                   //社員番号=3, 氏名=田中, 年齢=26
    }

    2. Select句について

     LINQのWhere句はリレーショナルデータベースの「選択、射影、結合」の3つの操作のうち「選択」に相当するものと言えます。一方でデータベースの「射影」に相当するものとしてSelect句があります。「1.Whereについて」で登場した社員リストの中から、社員名だけを抽出するようなプログラムを書いてみましょう。

    - code.5 -
    static void Main(string[] args)
    {
        var employeeList = new List<Employee>();
        employeeList.Add(new Employee() { EmployeeId = 1, EmployeeName = "鈴木", Age = 24 });
        employeeList.Add(new Employee() { EmployeeId = 2, EmployeeName = "佐藤", Age = 25 });
        employeeList.Add(new Employee() { EmployeeId = 3, EmployeeName = "田中", Age = 26 });
    
        List<string> employeeNameList = employeeList.Select(m => m.EmployeeName).ToList();
        employeeNameList.ForEach(m => Console.WriteLine(m));
        Console.ReadKey();
    }
    コンソールに次のように出力されていれば、正しくコードが実装されています。
    - コンソールの出力結果1 -
    鈴木
    佐藤
    田中