クエリ構文がなくて残念。DefaultIfEmpty()
メソッドを使う。
成果物
コード
using System; using System.Collections.Generic; using System.Linq; class Person { public string Name { get; set; } } class Pet { public string Name { get; set; } public Person Owner { get; set; } } class Main { private List<Person> persons; private List<Pet> pets; public void Run() { persons = CreatePersons(); pets = CreatePets(); Show(Query()); } private List<Person> CreatePersons() { return new List<Person>() { new Person { Name="A" }, new Person { Name="B" }, new Person { Name="C" }, }; } private List<Pet> CreatePets() { return new List<Pet>() { new Pet { Name="a", Owner=persons[0] }, new Pet { Name="b", Owner=persons[0] }, new Pet { Name="c", Owner=persons[1] }, new Pet { Name="z", Owner=null }, }; } private IEnumerable<dynamic> Query() { return from person in persons join pet in pets on person equals pet.Owner into gj from subpet in gj.DefaultIfEmpty() select new { person.Name, PetName=subpet?.Name ?? String.Empty }; } private void Show(in IEnumerable<dynamic> query) { foreach (var item in query) { Console.WriteLine($"Name={item.Name}, PetName={item.PetName}"); /* Console.WriteLine($"OwnerName={item.OwnerName}"); foreach (var pet in item.Pets) { Console.WriteLine($" PetName={pet.Name}"); } */ } } }
Name=A, PetName=a Name=A, PetName=b Name=B, PetName=c Name=C, PetName=
左外部結合なので左側があれば右側にひとつもなかったとしても1行取得される。ただしそのとき右側の値は空。
LINQで残念なのは、これをすべてメソッド形式で表現せねばならない上に、null時の値まで指定せねばならないこと。一気に面倒になった。
SQLで書いたら?
SQLで左外部結合を書くと以下のような感じ。
SELECT person.Name FROM Persons person LEFT OUTER JOIN Pets pet ON person.Id = pet.OwnerId
ちなみに以前学習したSQLite3では外部結合ができない仕様。PostgleQLなどならできるはずだが未確認。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13 ※
- bash 4.4.12(1)-release ※
- SQLite 3.29.0 ※
- C# dotnet 3.0.100 ※
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux