方法 : 内部結合を実行する (C# プログラミング ガイド)

リレーショナル データベース用語の内部結合では、2 番目のコレクション内の一致するすべての要素に対して、最初のコレクションの各要素が一度に表示される結果セットが生成されます。 2 番目のコレクションと一致する要素が最初のコレクションにない場合、その要素は結果セットに表示されません。 Join メソッドは、C# の join 句で呼び出され、内部結合を実装します。

このトピックでは、次の 4 種類の内部結合を実行する方法を示します。

  • 簡単なキーに基づいて、2 つのデータ ソースの要素を関連付ける単純な内部結合。

  • 複合キーに基づいて、2 つのデータ ソースの要素を関連付ける内部結合。 複合キーは複数の値で構成され、複数のプロパティに基づいて要素を関連付けることができます。

  • 一連の結合操作が相互に連結された複数の結合。

  • グループ結合を使用して実装された内部結合。

使用例

簡単なキーの結合の例

次の例は、2 つのユーザー定義型 Person と Pet のオブジェクトが含まれた 2 つのコレクションを作成します。 クエリでは、C# の join 句を使用して、Person オブジェクトを Owner がその Person である Pet オブジェクトと一致させます。 C# の select 句では、クエリ結果のオブジェクトの表示内容を定義します。 この例では、クエリ結果のオブジェクトは、飼い主の姓とペットの名前で構成された匿名型です。

        class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        class Pet
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        /// <summary> 
        /// Simple inner join. 
        /// </summary> 
        public static void InnerJoinExample()
        {
            Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
            Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
            Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
            Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
            Person rui = new Person { FirstName = "Rui", LastName = "Raposo" };

            Pet barley = new Pet { Name = "Barley", Owner = terry };
            Pet boots = new Pet { Name = "Boots", Owner = terry };
            Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
            Pet bluemoon = new Pet { Name = "Blue Moon", Owner = rui };
            Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

            // Create two lists.
            List<Person> people = new List<Person> { magnus, terry, charlotte, arlene, rui };
            List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

            // Create a collection of person-pet pairs. Each element in the collection 
            // is an anonymous type containing both the person's name and their pet's name. 
            var query = from person in people
                        join pet in pets on person equals pet.Owner
                        select new { OwnerName = person.FirstName, PetName = pet.Name };

            foreach (var ownerAndPet in query)
            {
                Console.WriteLine("\"{0}\" is owned by {1}", ownerAndPet.PetName, ownerAndPet.OwnerName);
            }
        }

        // This code produces the following output: 
        // 
        // "Daisy" is owned by Magnus
        // "Barley" is owned by Terry
        // "Boots" is owned by Terry
        // "Whiskers" is owned by Charlotte
        // "Blue Moon" is owned by Rui

LastName が "Huff" の Person オブジェクトは、Pet.Owner がその Person に等しい Pet オブジェクトがないため、結果セットに表示されません。

複合キーの結合の例

1 つのプロパティだけに基づいて要素を関連付ける代わりに、複合キーを使用して、複数のプロパティに基づいて要素を比較できます。 これを行うには、各コレクションに対してキー セレクター関数を指定し、比較するプロパティで構成された匿名型を返します。 プロパティにラベルを付ける場合は、各キーの匿名型に同じラベルを付ける必要があります。 また、プロパティは、同じ順序で表示する必要があります。

次の例は、Employee オブジェクトのリストと Student オブジェクトのリストを使用して、学生でもある社員を調べます。 これらの型の両方に、String 型の FirstName プロパティと LastName プロパティがあります。 それぞれのリストの要素から結合キーを作成する関数が、各要素の FirstName プロパティと LastName プロパティで構成された匿名型を返します。 結合操作で、これらの複合キーが等しいかどうか比較され、それぞれのリストの氏名が一致するオブジェクトのペアが返されます。

        class Employee
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int EmployeeID { get; set; }
        }

        class Student
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int StudentID { get; set; }
        }

        /// <summary> 
        /// Performs a join operation using a composite key. 
        /// </summary> 
        public static void CompositeKeyJoinExample()
        {
            // Create a list of employees.
            List<Employee> employees = new List<Employee> {
                new Employee { FirstName = "Terry", LastName = "Adams", EmployeeID = 522459 },
                 new Employee { FirstName = "Charlotte", LastName = "Weiss", EmployeeID = 204467 },
                 new Employee { FirstName = "Magnus", LastName = "Hedland", EmployeeID = 866200 },
                 new Employee { FirstName = "Vernette", LastName = "Price", EmployeeID = 437139 } };

            // Create a list of students.
            List<Student> students = new List<Student> {
                new Student { FirstName = "Vernette", LastName = "Price", StudentID = 9562 },
                new Student { FirstName = "Terry", LastName = "Earls", StudentID = 9870 },
                new Student { FirstName = "Terry", LastName = "Adams", StudentID = 9913 } };

            // Join the two data sources based on a composite key consisting of first and last name, 
            // to determine which employees are also students.
            IEnumerable<string> query = from employee in employees
                                        join student in students
                                        on new { employee.FirstName, employee.LastName }
                                        equals new { student.FirstName, student.LastName }
                                        select employee.FirstName + " " + employee.LastName;

            Console.WriteLine("The following people are both employees and students:");
            foreach (string name in query)
                Console.WriteLine(name);
        }

        // This code produces the following output: 
        // 
        // The following people are both employees and students: 
        // Terry Adams 
        // Vernette Price

複数の結合の例

任意の数の結合操作を相互に連結して、複数の結合を実行できます。 C# の各 join 句は、指定されたデータ ソースを前の結合の結果に関連付けます。

次の例は、Person オブジェクトのリスト、Cat オブジェクトのリスト、および Dog オブジェクトのリストの 3 つのコレクションを作成します。

C# の最初の join 句では、Person オブジェクトと Cat.Owner の照合に基づいて飼い主と猫を一致させます。 この操作で、Person オブジェクトと Cat.Name が含まれた匿名型のシーケンスが返されます。

C# の 2 番目の join 句では、Person 型の Owner プロパティと動物の名前の最初の文字で構成される複合キーに基づいて、最初の結合で返された匿名型を、指定された犬のリストの Dog オブジェクトに関連付けます。 この操作で、一致するそれぞれのペアの Cat.Name プロパティと Dog.Name プロパティが含まれた匿名型のシーケンスが返されます。 これは内部結合であるため、2 番目のデータ ソースと一致する、最初のデータ ソースのオブジェクトのみが返されます。

        class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        class Pet
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        class Cat : Pet
        { }

        class Dog : Pet
        { }

        public static void MultipleJoinExample()
        {
            Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
            Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
            Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
            Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
            Person rui = new Person { FirstName = "Rui", LastName = "Raposo" };
            Person phyllis = new Person { FirstName = "Phyllis", LastName = "Harris" };

            Cat barley = new Cat { Name = "Barley", Owner = terry };
            Cat boots = new Cat { Name = "Boots", Owner = terry };
            Cat whiskers = new Cat { Name = "Whiskers", Owner = charlotte };
            Cat bluemoon = new Cat { Name = "Blue Moon", Owner = rui };
            Cat daisy = new Cat { Name = "Daisy", Owner = magnus };

            Dog fourwheeldrive = new Dog { Name = "Four Wheel Drive", Owner = phyllis };
            Dog duke = new Dog { Name = "Duke", Owner = magnus };
            Dog denim = new Dog { Name = "Denim", Owner = terry };
            Dog wiley = new Dog { Name = "Wiley", Owner = charlotte };
            Dog snoopy = new Dog { Name = "Snoopy", Owner = rui };
            Dog snickers = new Dog { Name = "Snickers", Owner = arlene };

            // Create three lists.
            List<Person> people =
                new List<Person> { magnus, terry, charlotte, arlene, rui, phyllis };
            List<Cat> cats =
                new List<Cat> { barley, boots, whiskers, bluemoon, daisy };
            List<Dog> dogs =
                new List<Dog> { fourwheeldrive, duke, denim, wiley, snoopy, snickers };

            // The first join matches Person and Cat.Owner from the list of people and 
            // cats, based on a common Person. The second join matches dogs whose names start 
            // with the same letter as the cats that have the same owner. 
            var query = from person in people
                        join cat in cats on person equals cat.Owner
                        join dog in dogs on  
                        new { Owner = person, Letter = cat.Name.Substring(0, 1) }
                        equals new { dog.Owner, Letter = dog.Name.Substring(0, 1) }
                        select new { CatName = cat.Name, DogName = dog.Name };

            foreach (var obj in query)
            {
                Console.WriteLine(
                    "The cat \"{0}\" shares a house, and the first letter of their name, with \"{1}\".", 
                    obj.CatName, obj.DogName);
            }
        }

        // This code produces the following output: 
        // 
        // The cat "Daisy" shares a house, and the first letter of their name, with "Duke".
        // The cat "Whiskers" shares a house, and the first letter of their name, with "Wiley".

グループ結合を使用した内部結合の例

グループ結合を使用して内部結合を実装する方法を次の例に示します。

query1 で、Person オブジェクトのリストは、Pet.Owner プロパティと一致する Person に基づいて、Pet オブジェクトのリストにグループ結合されます。 グループ結合によって、それぞれのグループが Person オブジェクトおよび一致する Pet オブジェクトのシーケンスで構成された、中間グループのコレクションが作成されます。

2 つ目の from 句をクエリに追加すると、シーケンスのこのシーケンスが 1 つの長いシーケンスに結合 (または平坦化) されます。 最後のシーケンスの要素の型は、select 句で指定されます。 この例では、この型は、一致する各ペアの Person.FirstName プロパティと Pet.Name プロパティで構成された匿名型です。

query1 の結果は、into 句のない join 句を使用して内部結合を実行することで得られた結果セットと同じです。 query2 変数は、これと同等のクエリを示しています。

        class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        class Pet
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        /// <summary> 
        /// Performs an inner join by using GroupJoin(). 
        /// </summary> 
        public static void InnerGroupJoinExample()
        {
            Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
            Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
            Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
            Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

            Pet barley = new Pet { Name = "Barley", Owner = terry };
            Pet boots = new Pet { Name = "Boots", Owner = terry };
            Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
            Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
            Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

            // Create two lists.
            List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
            List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

            var query1 = from person in people
                         join pet in pets on person equals pet.Owner into gj
                         from subpet in gj
                         select new { OwnerName = person.FirstName, PetName = subpet.Name };

            Console.WriteLine("Inner join using GroupJoin():");
            foreach (var v in query1)
            {
                Console.WriteLine("{0} - {1}", v.OwnerName, v.PetName);
            }

            var query2 = from person in people
                         join pet in pets on person equals pet.Owner
                         select new { OwnerName = person.FirstName, PetName = pet.Name };

            Console.WriteLine("\nThe equivalent operation using Join():");
            foreach (var v in query2)
                Console.WriteLine("{0} - {1}", v.OwnerName, v.PetName);
        }

        // This code produces the following output: 
        // 
        // Inner join using GroupJoin(): 
        // Magnus - Daisy 
        // Terry - Barley 
        // Terry - Boots 
        // Terry - Blue Moon 
        // Charlotte - Whiskers 
        // 
        // The equivalent operation using Join(): 
        // Magnus - Daisy 
        // Terry - Barley 
        // Terry - Boots 
        // Terry - Blue Moon 
        // Charlotte - Whiskers

コードのコンパイル

  • Visual Studio で新しいコンソール アプリケーション プロジェクトを作成します。

  • System.Core.dll がまだ参照されていない場合は、System.Core.dll への参照を追加します。

  • System.Linq 名前空間を含めます。

  • 例からコードをコピーし、program.cs ファイルの Main メソッドの下に貼り付けます。 貼り付けたメソッドを呼び出すコード行を Main メソッドに追加します。

  • プログラムを実行します。

参照

処理手順

方法 : グループ化結合を実行する (C# プログラミング ガイド)

方法 : 左外部結合を実行する (C# プログラミング ガイド)

方法 : 2 つのコレクションを結合する (C#) (LINQ to XML)

関連項目

Join

GroupJoin

匿名型 (C# プログラミング ガイド)

概念

結合演算

匿名型 (Visual Basic)