# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.saladpuk.com/beginner-1/csharp101/advanced/linq.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
