> For the complete documentation index, see [llms.txt](https://www.saladpuk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.saladpuk.com/beginner-1/csharp101/advanced/linq.md).

# LINQ

ในบทนี้เราจะมาทำความรู้จักกับ**หนึ่งในความสามารถที่ทรงพลังที่สุดของภาษา C#** เลยก็ได้ว่า นั่นก็คือเจ้าสิ่งที่เรียกว่า **LINQ** ซึ่งย่อมาจาก **Language Integrated Query** นั่นเอง โดยเจ้าตัวนี้เป็นหนึ่งมหากาพย์ที่ทำให้เราลดโค้ดจากร้อยๆบรรทัดให้เหลือแค่เพียงไม่กี่บรรทัดได้ และยัง**ช่วยให้โค้ดที่เขียนกลายเป็น Clean Code อีกด้วย**นะ เราลองไปทำความเข้าใจเรื่องของ **LINQ** กันเลยเลยดีกว่าครัช

{% hint style="warning" %}
ถ้าคิดว่าใช้งาน LINQ คล่องแล้ว และรู้จักการทำงานแบบ **Declarative** กับ **Imperative** ของ LINQ และการทำ **Chain** แล้วละก็ข้ามเรื่องนี้ไปได้เลย
{% endhint %}

{% hint style="success" %}
**LINQ**\
มีหลายคนเลยสงสัยว่ามันออกเสียงว่ายังไง เจ้าตัวนี้ออกเสียงว่า **ลิงค์** ครับ (อ้างจากสำเนียงเมกา) ไม่ได้ออกเสียงว่า ~~ลิน~~ หรือ ~~ลินคิว~~ ใดๆทั้งสิ้น จำง่ายๆว่ามันออกเสียงเหมือน link ที่ไม่ออกเสียงตัว k อ่ะ
{% endhint %}

## 🤔 LINQ คือไรหว่า ?

แบบสั้นๆก่อนเจ้า LINQ คือ ชุดคำสั่งที่จะทำให้เราทำงานกับกลุ่มของข้อมูลได้ง่ายๆ เช่น ทำงานกับ ข้อมูลที่ดึงมาจากฐานข้อมูล ทำงานกับ XML หรือพวก collection ต่างๆ โดยมีภาษาที่ใกล้เคียงกับ **SQL syntax** นั่นเอง

## 🤔 LINQ ใช้ไงหว่า ?

ซึ่งจากประสบการณ์ที่ผมไปสอนมาพบว่า เราไปดูตัวอย่างกันแล้วจะเข้าใจ LINQ ได้เร็วกว่าอ่านทฤษฎีครับ ดังนั้นผมจะใช้ตัวอย่างนี้อธิบายเอานะ โดยโจทย์ของผมคือถ้าผมมีข้อมูลตัวเลข 1\~7 อยู่ใน array ตามโค้ดด้านล่าง

```csharp
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
```

แล้วถ้าเกิดผมอยาก**ดึงเฉพาะเลขคู่**ออกมาจากตัวแปร `numbers` ล่ะต้องทำยังไง ? ซึ่งถ้าเขียนโค้ดแบบปรกติเราก็จะเขียนออกมาได้ราวๆนี้

#### 🔥 **เขียนแบบปรกติ**

ผมก็จะสร้าง array ขึ้นใหม่ เพื่อเอาไว้เก็บค่าเฉพาะเลขคู่ไว้ยังไงล่ะ ตามโค้ดด้านล่างเลย

```csharp
var evenIndex = 0;
var evenNumbers = new int[3];
for (int i = 0; i < numbers.Length; i++)
{
    if (numbers[i] % 2 == 0)
    {
        evenNumbers[evenIndex++] = numbers[i];
    }
}
```

#### 🔥 **เขียนแบบใช้ LINQ**

คราวนี้เราก็จะมาลองเอา **LINQ** มาแก้โจทย์เดียวกันดูบ้างนะ ซึ่งการที่จะใช้ LINQ ได้นั้นเราจะต้องเรียกใช้ **`using System.Linq;`** ไว้ด้านบนสุดด้วยนะ และการเขียน LINQ เราสามารถเขียนได้ 2 วิธีตามนี้

**1.เขียน LINQ แบบเต็มๆ**

```csharp
var evenNumbers = from it in numbers
                  where it % 2 == 0
                  select it;
```

ตาไม่ได้ฝาดไปหรอกครับ โค้ดมันเหลือแค่นั้นจริงๆ และมันเขียนแทบจะเหมือนภาษา **SQL syntax** เลยยังไงล่ะ ดังนั้นใครที่เขียน SQL syntax เป็นอยู่แล้วรับรองครับว่าสบายเลย

> **อธิบายโค้ดตามบรรทัด**\
> **บรรทัดที่ 1**\
> เราเลือกว่าจะทำงานกับกลุ่มข้อมูลตัวไหน ซึ่งในที่นี้คือ **numbers** นั่นเอง โดยข้อมูลแต่ละตัวในกลุ่มข้อมูลนั้นเราจะใช้ตัวแปรที่ชื่อว่า **it** เข้าไปไล่ค่ามัน (เหมือน foreach แหละ)\
> **บรรทัดที่ 2**\
> เราทำการคัดกรองเอาเฉพาะข้อมูลตัวที่มันถูกหารด้วย 2 ลงตัวเท่านั้น ด้วยคำสั่ง where\
> **บรรทัดที่ 3**\
> ข้อมูลไหนที่ผ่านเงื่อนไขจากบรรทัดที่ 2 เราจะทำการเอาข้อมูลเหล่านั้นมาใช้

**2.เขียน LINQ แบบย่อๆ**\
ที่เห็นมันสั้นแล้วจริงๆมันยังเขียนให้กระชับลงได้อีกตามโค้ดด้านล่างเลย

```csharp
var evenNumbers = numbers.Where(it => it % 2 == 0);
```

ไม่ว่าจะเป็น **แบบเต็ม** หรือ **แบบย่อ** การทำงานมันเหมือนกันครับ ขึ้นอยู่กับว่าถนัดแบบไหน ซึ่งปรกติ**ผมแนะนำว่าให้เขียนแบบย่อครับ**

{% hint style="success" %}
**Clean Code**\
จะเห็นว่าไม่ว่าจะเขียนแบบเต็มหรือแบบย่อนั้น มันอ่านง่ายสบายตากว่า การเขียนแบบปรกติเยอะม๊วกกกก ดังนั้นการทำงานอะไรก็แล้วแต่ที่ทำงานกับกลุ่มข้อมูล ผมแนะนำว่าให้ใช้ LINQ ไปเลยถ้าใช้ได้
{% endhint %}

## 🤔 หัวใจของ LINQ มีไรบ้าง ?

อยากเขียน LINQ เป็นจริงๆนั้นง่ายมาก เพราะ LINQ มีหัวใจการทำงานแค่ 3 เรื่องเท่านั้น  โดยผมจะใช้โค้ดที่ใช้แก้โจทญืในตอนแรก มาเขียนกำกับหัวใจการทำงานลงไปละกัน ชึบๆ

```csharp
// 1. Data source
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };

// 2.Query
var evenNumbers = numbers.Where(it => it % 2 == 0);

// 3.Query execution
foreach (int item in evenNumbers)
{
    Console.WriteLine(item);
}
```

ซึ่งจากโค้ดด้านบนจะเห็นว่ามันมีการแบ่งงานออกเป็น 3 เรื่องคือ

### 🔥 Data Source

คือ**กลุ่มข้อมูลที่เราต้องการจะทำงานด้วย** ซึ่งกลุ่มข้อมูลในที่นี้คืออะไรก็ได้ที่เป็นตระกูล collection ที่มาจาก **IEnumerable** นั้นเอง ซึ่ง array ก็เป็นหนึ่งในนั้น เราเลยสามารถใช้ LINQ ทำงานด้วยได้

### 🔥 Query

คือ**คำสั่งที่เราต้องการจะไปกระทำกับ Data Source ของเรา** ซึ่งจากโค้ดตัวอย่างคือเราจะทำการ filter เอาเฉพาะข้อมูลตัวที่ 2 หารลงตัวนั่นเอง

### 🔥 Query execution

คือ**ตัวสั่งให้ query ที่เราเตรียมไว้มันเริ่มทำงาน** ซึ่งในโค้ดคือเจ้า **foreach** นั่นเอง มันจะเป็นตัวกระตุ้นให้โปรแกรมเริ่มวิ่งเข้าไปที่ data source เพื่อดึงข้อมูลมาตาม query ที่เขียนไว้

{% hint style="danger" %}
**Query Execution**\
เจ้า query execution นี้มีการทำงานทั้งหมด 2 รูปแบบคือ **Deferred Execution** และ **Forcing Immediate Execution** เดี๋ยว ซึ่งทั้ง 2 แบบนี้จะต่างกันอย่างสิ้นเชิง และทำให้เหล่า developer สาย .NET ตกม้าตายมาเยอะแล้ว ซึ่งมันคือผมขอไปอธิบายไว้ด้านล่างๆครัช
{% endhint %}

## 🤔 อยากเขียน LINQ ต้องทำไง ?

เราก็แค่เรียนรู้ว่า LINQ มันสามารถเล่นอะไรกับกลุ่มของข้อมูลได้บ้างเพียงเท่านี้ก็ใช้ LINQ ได้เลย ส่วนถ้าอยากรีดศักยภาพมากขึ้นเราต้องเข้าใจการใช้ [`Lambda`](https://saladpuk.gitbook.io/learn/beginner-1/csharp101/advanced/lambda-expression) กับ [`Generic`](https://saladpuk.gitbook.io/learn/beginner-1/csharp101/advanced/generic) ด้วยจะดีมาก ดังนั้นเราลองไปดูว่า LINQ ทำอะไรกับกลุ่มของข้อมูลได้บ้างกัน&#x20;

### 🔥 คัดกรองข้อมูล (Filtering)

ถ้าเราอยากคัดกรองข้อมูลให้มันเอาเฉพาะของที่เราอยากได้เท่านั้นออกมา เราสามารถใช้คำสั่ง **`Where`** ในการคัดกรองได้ เช่น ถ้าเรามีโค้ดเป็นแบบนี้

```csharp
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
```

แล้วเราอยากได้เฉพาะตัวเลขที่มากกว่า 4 ขึ้นไป เราก็จะเขียนโค้ดออกมาเป็นตามนี้

```csharp
// เขียนแบบเต็ม
var fullQry = from it in numbers
              where it > 4
              select it;

// เขียนแบบย่อ
var shortenQry = numbers.Where(it => it > 4);
```

> ผลลัพท์ { 5, 6, 7 }

หรือเราอยากคัดกรองเอาเฉพาะ เลขคี่ ที่มากกว่า 2 ขึ้นไป

```csharp
// เขียนแบบเต็ม
var fullQry = from it in numbers
              where it % 2 != 0 && it > 2
              select it;
              
// เขียนแบบย่อ
var shortenQry = numbers.Where(it => it % 2 != 0 && it > 3);
```

> ผลลัพท์ { 3, 5, 7 }

### 🔥 เรียงลำดับ (Ordering)

ในกรณีที่ data source ของเราไม่ได้เรียงลำดับมา เราสามารถทำให้มันเรียงลำดับให้เราได้ เช่นผมมี data source เป็นแบบนี้

```csharp
var numbers = new int[] { 7, 5, 3, 1, 6, 2, 4 };
```

เรียงจากน้อยไปมาก

```csharp
// เขียนแบบเต็ม
var fullQry = from it in numbers
              orderby it
              select it;

// เขียนแบบย่อ
var shortenQry = numbers.OrderBy(it => it);
```

> ผลลัพท์ { 1, 2, 3, 4, 5, 6, 7 }

เรียงจากมากไปหาน้อย

```csharp
// เขียนแบบเต็ม
var fullQry = from it in numbers
              orderby it descending
              select it;

// เขียนแบบย่อ
var shortenQry = numbers.OrderByDescending(it => it);
```

> ผลลัพท์ { 7, 6, 5, 4, 3, 2, 1 }

### 🔥 จัดกลุ่ม (Grouping)

เราสามารถสร้างทำให้มันแบ่งข้อมูลออกเป็นกลุ่มๆตามเงื่อนไขได้ เช่น จากโค้ดตัวนี้

```csharp
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
```

ผมต้องการจะให้มันแบ่งออกเป็น 2 กลุ่มคือ กลุ่มเลขคู่ กับ กลุ่มเลขคี่ ก็จะเขียนออกมาได้ประมาณนี้ (ขี้เกียจเขียนแบบเต็มแล้วนะ)

```csharp
var qry = numbers.GroupBy(it => it % 2 == 0);
```

> ผลลัพท์\
> กลุ่ม false จะมีข้อมูลเป็น 1, 3, 5, 7\
> กลุ่ม true จะมีข้อมูลเป็น 2, 4, 6

เอาเท่านี้ก่อนละกัน เพราะไม่งั้นมันจะเยอะมากจนบทความนี้อาจจะอ่านแล้วกระตุกเลย ผมขอเอาคำสั่งทั้งหมดไปเขียนสรุปไว้ในหัวข้อถัดไปเลยละกัน

## 🤔 LINQ ทำไรได้บ้าง ?

ความสามารถแค่ส่วนหลักๆของ LINQ ที่เราจะได้ใช้กันขอสรุปเป็นตารางไว้แบบนี้ละกัน

{% hint style="info" %}
**แนะนำให้อ่าน**\
ตัวอย่างการทำงานจริงๆของแต่ละคำสั่งคืออะไร สามารถไปอ่านได้จากบทความนี้นะ [พระคัมภีร์การใช้คำสั่ง LINQ](https://saladpuk.gitbook.io/learn/beginner-1/csharp101/advanced/linq-demo)
{% endhint %}

### คำสั่งที่เอาไว้ทำงานกับ collection

กลุ่มนี้ทั้งหมดเป็น Deferred Execution - คืออะไรไปอ่านต่อได้จากด้านล่าง

| คำสั่ง            | ใช้สำหรับ                           | ผลลัพท์    |
| ----------------- | ----------------------------------- | ---------- |
| Where             | กรองข้อมูล                          | Collection |
| Select            | เลือก                               | Collection |
| Distinct          | ตัดตัวซ้ำ                           | Collection |
| Take              | เอา                                 | Collection |
| Skip              | ข้าม                                | Collection |
| SkipWhile         | ข้ามจนกว่า                          | Collection |
| TakeWhile         | เอาจนกว่า                           | Collection |
| OrderBy           | เรียงลำดับ น้อย-มาก                 | Collection |
| OrderByDescending | เรียงลำดับ มาก-น้อย                 | Collection |
| Reverse           | เรียงลำดับกลับด้าน                  | Collection |
| Union             | รวม 2 collection เข้าด้วยกัน        | Collection |
| Intersect         | เอาเฉพาะตัวที่ซ้ำกันใน 2 collection | Collection |
| Except            | ตัดตัวที่ซ้ำกับ collection อื่น     | Collection |

### คำสั่งที่ได้ผลลัพท์กลับมาเลย

กลุ่มนี้ทั้งหมดเป็น Forcing Immediate Execution - คืออะไรไปอ่านต่อได้จากด้านล่าง

| คำสั่ง         | ใช้สำหรับ                           | ผลลัพท์        |
| -------------- | ----------------------------------- | -------------- |
| Count          | นับว่ามีกี่ตัว                      | number         |
| Sum            | หาผลรวม                             | number         |
| Min            | หาค่าน้อยสุด                        | number         |
| Max            | หาค่ามากสุด                         | number         |
| Average        | หาค่าเฉลี่ย                         | number         |
| First          | เอาข้อมูลตัวแรก                     | T              |
| FirstOrDefault | เอาข้อมูลตัวแรก ถ้าไม่เจอขอ default | T หรือ default |
| Any            | ดูว่ามีซักตัวไหมที่ตรงเงื่อนไข      | bool           |
| All            | ทุกตัวตรงเงื่อนไขหรือไม่            | bool           |
| Contains       | ใน collection มีตัวนี้หรือเปล่า     | bool           |

### คำสั่งในการแปลง collection

กลุ่มนี้ทั้งหมดเป็น Forcing Immediate Execution - คืออะไรไปอ่านต่อได้จากด้านล่าง

| คำสั่ง       | ใช้สำหรับ                  | ผลลัพท์           |
| ------------ | -------------------------- | ----------------- |
| ToArray      | แปลงเป็น Array\<T>         | Array\<T>         |
| ToList       | แปลงเป็น List\<T>          | List\<T>          |
| ToDictionary | แปลงเป็น Dictionary\<K, V> | Dictionary\<K, V> |

## 💡 Deferred vs Immediate

จากที่เคยอธิบายไปว่า LINQ มีการสั่ง execution ทั้งหมด 2 รูปแบบนั่นคือ **Deferred Execution** และ **Forcing Immediate Execution** ซึ่งทั้งสองตัวนี้แตกต่างกันสิ้นเชิง เพราะมันเกิดมาจาก 2 แนวคิดในการเขียนโค้ดนั่นเอง

{% hint style="info" %}
**แนะนำให้อ่าน**\
เจ้า 2 แนวคิดที่ว่านั่นคือ **Functional Programming** กับ **Imperative Programming** นั่นเอง ซึ่งสามารถอ่านมันได้เต็มๆได้จากลิงค์นี้เบย\
[Microsoft document - Functional vs Imperative](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/functional-programming-vs-imperative-programming)
{% endhint %}

ซึ่งการทำงานของ LINQ มันจะได้ผลลัพท์กลับมาทั้งหมด 2 แบบ โดยแต่ละแบบทำงานกันแบบนี้

### 🔥 **Forcing Immediate Execution**

เป็นแบบที่เราคุ้นเคยกันที่สุด นั่นคือเป็นการสั่งออกไปแล้วได้ผลลัพท์กลับมาทันทีนั่นเอง (ดูกลุ่มคำสั่งนี้ได้จากตารางด้านบน) เช่น โค้ดด้านล่างนี้ เป็นการหาค่าสูงสุดของข้อมูลใน collection

```csharp
var numbers = new int[] { 7, 5, 3, 1, 6, 2, 4 };
// Forcing Immediate Execution
var result = numbers.Max();
```

> ผลลัพท์ result = 7

### 🔥 **Deferred Execution**

เป็นคำสั่งที่จะไม่ทำงานจนกว่าจะผ่านจุดที่เกิด Query Execution ขึ้นเท่านั้น ซึ่งคำสั่งตระกูลนี้จะได้ผลลัพท์กลับมาเป็น collection ของ IEnumerable\<T> นั่นเอง (ดูกลุ่มคำสั่งนี้ได้จากตารางด้านบน) เช่นโค้ดตัวอย่างจะทำการดึงค่าเฉพาะเลขคู่ออกมาเท่านั้น แต่ผมจะเพิ่มว่าทุกๆ loop มันจะมีตัวนับเลขถูกเพิ่มค่าเข้าไปเรื่อยๆ ตามนี้

```csharp
var runner = 0;
var qry = numbers.Where(it => it % 2 == 0 && runner++ > 0);
Console.WriteLine(runner);
```

คำถามคือ `runner` มีค่าเป็นเท่าไหร่ถ้าผม run โค้ดเพียงเท่านี้เป๊ะๆเลย ?

> เฉลย runner จะมีค่าเป็น 0 ครับ

เพราะคำสั่งในกลุ่มนี้มันเป็นการจำว่ามันจะต้องไปทำอะไรกับ data source อย่างเดียวเท่านั้น มันจะไม่ดำเนินการอะไรเลย จนกว่ามันจะผ่าน **Query Execution** ซักตัวนั่นเอง

จากที่ว่ามาผมก็เลยเพิ่ม query execution แบบง่ายๆเข้าไปนั่นคือ **foreach** แบบโง่ๆเลยตามนี้

```csharp
var runner = 0;
var qry = numbers.Where(it => it % 2 == 0 && runner++ > 0);
Console.WriteLine($"Before Query Execution, Runner: {runner}");
foreach (var item in qry)
{
}
Console.WriteLine($"After Query Execution, Runner: {runner}");
```

คำถามคือ ในบรรทัดที่ 3 กับบรรทัดที่ 7 มันจะโชว์เลขอะไรออกมา ?

> เฉลย\
> Before Query Execution, Runner: 0\
> After Query Execution, Runner: 3

สาเหตุที่บรรทัดที่ 3 มันโชว์เลข 0 เพราะค่า query มันยังไม่ผ่าน Query Execution นั่นเอง ส่วนบรรทัดที่ 7 ที่มีนโชว์เลข 3 เพราะมันผ่าน Query Execution แล้วนั่นเองมันเลยไปเพิ่มค่า runner ยังไงล่ะ

### 🔥 **Deferred Execution + Forcing Immediate Execution**

ถ้าในกรณีที่เราเขียนคำสั่งเป็น **Deferred Execution** แต่เราจบด้วย **Forcing Immediate Execution** แล้วล่ะก็ มันจะกลายเป็น **Forcing Immediate Execution** โดยทันที เช่นโค้ดเดิมด้านบน ผมเอามาเขียนให้มันจบโดยใช้คำสั่ง **`.Count()`** ซึ่งเป็นคำสั่งของ forcing immediate execution ผมจะได้ผลลัพท์ออกมาแบบนี้

```csharp
var runner = 0;
var qry = numbers.Where(it => it % 2 == 0 && runner++ > 0).Count();
Console.WriteLine($"Runner: {runner}");
```

> ผลลัพท์\
> Runner: 3

## 💡 Streaming vs Non-Streaming

ทุกๆครั้งที่เราไปดึงข้อมูลมาจาก data source เพื่อมาทำการประมวลผล มันจะมีการดึงข้อมูลมา 2 รูปแบบคือ

### 🔥 Streaming

เป็นการ**ดึงข้อมูลมาแบบต่อเนื่อง** โดยมันจะค่อยๆอ่านข้อมูลจาก data source มาทำการประมวลผลเรื่อยๆ ไม่ได้ดึงมาตูมเดียวทั้งหมดนั่นเอง ซึ่งเจ้าตัวนี้จะเหมาะใช้กับการทำงานกับ data source ที่มีขนาดใหญ่ๆ

### 🔥 Non-Streaming

เป็นการ**ดึงข้อมูลมาตูมเดียวจบ** แล้วทำการประมวลผลเลย

## 🤔 มีไรที่ควรรู้อีกไหม ?

เรื่องพื้นฐานสุดท้ายที่นึกออกละ คำสั่งพวก LINQ ทั้งหลายมันเป็น Extension Method ที่อยู่ใน namespace `System.Linq;` ดังนั้นมันหมายความว่า**คำสั่ง LINQ มันเชื่อมกันได้** เช่น ผมมี Data Source เป็นตัวเลข 1-100 ตามนี้

```csharp
var numbers = Enumerable.Range(1, 100);
```

แล้วผมต้องการข้อมูล 4 กลุ่มตามนี้

1. กลุ่มเลขคู่
2. กลุ่มเลขคู่ที่ 5 หารลงตัว
3. กลุ่มเลขคู่ที่ 7 หารลงตัว
4. กลุ่มเลขคู่ที่ 5 และ 7 หารลงตัว

เราก็จะสามารถใช้ความสามารถในการเชื่อมกันออกมาแบบนี้ได้

```csharp
// 1.กลุ่มเลขคู่
var evenNumberQry = numbers
    .Where(it => it % 2 == 0);

// 2.กลุ่มเลขคู่ที่ 5 หารลงตัว
var eventWithDividableBy5NumberQry = evenNumberQry
    .Where(it => it % 5 == 0);

// 3.กลุ่มเลขคู่ที่ 7 หารลงตัว
var eventWithDividableBy7NumberQry = evenNumberQry
    .Where(it => it % 7 == 0);

// 4.กลุ่มเลขคู่ที่ 5 และ 7 หารลงตัว
var eventWithDividableBy5N7NumberQry = 
    eventWithDividableBy5NumberQry
    .Union(eventWithDividableBy7NumberQry);
```

จะเห็นว่ากลุ่มที่เป็นเลขคู่จะใช้เป็นตัวตั้งต้นตัวแรก แล้วที่เหลือจะเอาผลลัพท์ของตัวแรกมาใช้ต่อเรื่อยๆได้ หรือในข้อ 4 เราจะเขียน **Chain** กันในรูปแบบนี้ก็ได้เหมือนกัน

```csharp
// 4.กลุ่มเลขคู่ที่ 5 และ 7 หารลงตัว
var eventWithDividableBy5N7NumberQry = evenNumberQry
                .Where(it => it % 5 == 0)
                .Where(it => it % 7 == 0);
```

## 🎯 บทสรุป

LINQ เป็นมหากาพย์ตัวนึงที่ดูเหมือนว่ามันจะเยอะมาก แต่ถ้าเราเข้าใจมันทั้งหมดแล้วเราจะพบว่า มันไม่มีอะไรเลย และไม่ต้องไปนั่งไล่จำอะไรเลย ขอแค่รู้หัวใจหลัก 3 เรื่องของมันก็พอ `Data Source` `Query` `Query Execution` เท่านั้นเอง เพียงเท่านี้โค้ดของเราก็จะกระชับและทรงพลังมาก เพราะมันสามารถไปเชื่อมใช้งานกับสิ่งต่างๆได้อีกเยอะเลย เช่น ทำ **Query Database** ทำงานร่วมกับ **Entity Framework** หรือแม้กระทั่งการทำงานกับ **Reactive** เช่น **Reactive Extension (Rx)** ก็ยังได้ คือจริงๆมันสารพัดประโยชน์มากจริงๆนะเจ้าตัวนี้ จนแทบจะเรียกว่าใครเขียน C# หากินเป็นอาชีพไม่รู้ไม่ได้

{% hint style="success" %}
**แนะนำให้อ่าน**\
ถ้าเพื่อนๆอยากเข้าใจการทำงานจริงๆของ LINQ หรือดูตัวอย่างหลายๆแบบแล้วล่ะก็สามารถเข้าไปดูเพิ่มเติมได้จากลิงค์ด้านล่างนี้เลยครัช (เนื้อหาแน่นปึก) และนอกจากนี้ยังมีตัวอย่างของภาษาอื่นๆอีกนะเช่น VB\
[Microsoft document - LINQ](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/)
{% endhint %}
