やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

C#の概念 LINQ(左外部結合)

 クエリ構文がなくて残念。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などならできるはずだが未確認。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux