ทำความรู้จัก LINQ [ตอน2]

Home Page  |   รายการบทความ   |   ลิงค์ที่เกี่ยวข้อง   |   laploy.com  |  เกี่ยวกับผู้เขียน

ตัวอย่างเนื้อหาของหนังสือ เรีนรู้ด้วยตนเอง LINQ

   [ตอน2]

 

ข้อดีของ LINQ
ก่อนหน้าที่จะมี LINQ การพัฒนาซอฟต์แวร์ที่เกี่ยวข้องกับแหล่งข้อมูลคละแบบ ท่านจำเป็นต้องใช้ API (Application Programming Interface ตัวเชื่อมต่อกับโปรแกรมประยุกต์) ที่แตกต่างกันหลายแบบ แต่ละแบบมีเทคโนโลยีและวิธีใช้งานเป็นของตัวเอง ยกตัวอย่างเช่นเมื่อท่านติดต่อกับ SQL2008 ท่านต้องใช้ ADO.NET เมื่อจะติดต่อกับแฟ้มข้อมูล XML ท่านต้องใช้ API ที่อยู่ภายในเนมสเปส System.Xml สภาพการเช่นนี้สร้างความปวดเศียรเวียนเกล้าให้แก่กรรมกรซอฟต์แวร์กันทั่วหน้า เพราะวิธีเขียนโค้ดติดต่อกับข้อมูลมีโมเดลหลายแบบ ขาดความคงเส้นคงวา ดีใจได้! เพราะต่อไปนี้จะไม่เป็นเช่นนั้นแล้ว LINQ จะช่วยให้ท่านทำงานกับแหล่งข้อมูลทุกชนิดได้ด้วยวิธีที่เหมือนๆ กันหมด

ความคงเส้นคงวาเช่นนี้ช่วยให้ชีวิตของกรรมกรซอฟต์แวร์สะดวกสบายขึ้นมาก เพราะเมื่อท่านชำชองวิธีติดต่อกับแหล่งข้อมูลชนิดหนึ่งแล้ว ท่านจะสามารถเขียนโค้ดติดต่อกับแหล่งข้อมูลชนิดอื่นได้โดยใช้ความรู้เดียวกัน ยกตัวอย่างเช่นเมื่อท่านช่ำชองวิธีคิวรีข้อมูลในอาร์เรย์ด้วย LINQ แล้ว ท่านจะสามารถคิวรีข้อมูลในฐานข้อมูลได้โดยไม่ต้องเรียนรู้วิธีทำใหม่ทั้งหมด เพราะนับว่าท่านได้เรียนแนวคิดแนวปฏิบัติที่สำคัญต่างๆ ใน LINQ ไปมิใช่เล็กน้อยแล้ว

ข้อดีอีกอย่างหนึ่งของ LINQ คือนอกจากท่านจะไม่ต้องห่วงว่าคิวรีจะผิดไวยากรณ์ เพราะตัวแปลภาษาจะตรวจสอบ และแจ้งความผิดพลาดให้อย่างที่เรียนไปแล้ว ส่วนอินเทลลิเซนส์ (IntelliSense คุณสมบัติเพื่อตรวจสอบความถูกต้องและเสนอแนะคำที่เหมาะขณะป้อนพิมพ์โค้ดของ VS2008) ยังสามารถทำงานกับ LINQ ได้อย่างก้าวหน้า ช่วยให้การป้อนพิมพ์โค้ดทำได้อย่างสนุก

เรื่องสำคัญที่ไม่ควรมองข้ามอีกประการหนึ่งคือ LINQ ไม่ได้ส่งผลกระทบต่อการทำงานกับข้อมูลเท่านั้น การผสาน LINQ เข้ากับ C# ยังทำให้ภาษา C# เปลี่ยนแปลงไปอย่างสู่รูปโฉมใหม่อีกด้วย วิธีเขียนโค้ดของท่านจะไม่เหมือนเดิมอีกต่อไปแล้ว เพราะในหนังสือเล่มนี้ท่านจะได้เรียนรู้วิธีใช้ประโยชน์จากความเปลี่ยนแปลงที่เกิดขึ้นอย่างกว้างขวางในภาษา C# ที่จะช่วยให้โค้ดของท่านสั้นกระชับแต่จะทรงพลังกว่าเดิม

ภาพ 1-6: ส่วนอินเทลลิเซนส์ (IntelliSense คุณสมบัติเพื่อตรวจสอบความถูกต้องและเสนอแนะคำที่เหมาะขณะป้อนพิมพ์โค้ดของ VS2008) ยังสามารถทำงานกับ LINQ ได้อย่างก้าวหน้า

ชุดเครื่องมือ LINQ
LINQ เหมือนเหรียญที่มีสองด้าน ในด้านหนึ่งมันเป็นชุดเครื่องมือเพื่อใช้ทำงานกับข้อมูล และในอีกด้านหนึ่งมันมีภาวะเป็นส่วนที่เพิ่มขยายความสามารถของภาษา C# ในหัวข้อนี้ผู้เขียนจะพูดถึง LINQ ในแง่ที่เป็นชุดเครื่องมือ ท่านอาจมองว่า LINQ เป็นกล่องเครื่องมือที่มีเครื่องมือมาให้หลายอย่างดังนี้

  • LINQ to Object: เป็นเครื่องมือที่ช่วยให้ท่านทำคิวรีกับข้อมูลที่อยู่ภายในดาต้าคอลเลคชันภายในหน่วยความจำ
  • LINQ to DataSet: เป็นเครื่องมือที่ช่วยให้ท่านทำคิวรีกับข้อมูลที่อยู่ภายในดาต้าเซต
  • LINQ to SQL: เป็นเครื่องมือที่ช่วยให้ท่านทำคิวรีกับข้อมูลที่อยู่ภายในฐานข้อมูล
  • LINQ to Entity: เป็นเครื่องมือที่ช่วยให้ท่านทำคิวรีกับข้อมูลที่อยู่ภายในออพเจ็กต์แบบ ADO.NET เอ็นทิตีเฟรมเวิร์ค
  • LINQ to XML: เป็นเครื่องมือที่ช่วยให้ท่านทำคิวรีกับข้อมูลที่อยู่ภายในแฟ้มข้อมูล XML

ในหนังสือเล่มนี้ท่านจะได้เรียนเครื่องมือที่ LINQ มีมาให้ทั้งห้าแบบนี้โดยละเอียด เครื่องมือห้าแบบนี้บางทีเรียกว่าตัวให้บริการหรือโพรไวเดอร์ (LINQ Provider ย่อ LP) ลองพิจารณาภาพ 1-7 จะเห็นว่าส่วนบนสุดคือภาษาที่ใช้งานกับ LINQ ได้ (ขณะนี้มีเพียงสองภาษาคือ C# 3.0 และ VB 9.0) ระดับถัดลงไปจากภาษาคือส่วนเพิ่มขยายหรือเปลี่ยนแปลงภาษาเพื่อให้ใช้งาน LINQ ได้ ประกอบด้วยสิ่งหลักสามสิ่งคือ ตัวดำเนินการคิวรีมาตรฐาน (Standard Query Operators ย่อ SQO) นิพจน์คิวรี (Query Expression ย่อ QE) และนิพจน์ต้นไม้ (Expression Tree ย่อ ET)

ถัดจากส่วนเพิ่มขยายหรือเปลี่ยนแปลงภาษาเพื่อให้ใช้งาน LINQ ได้คือ LP ประกอบด้วยตัวให้บริการห้าตัวคือ LINQ to Object, LINQ to XML, LINQ to SQL, LINQ to DataSet และ LINQ to Entities ในอนาคตทีมงานผู้สร้าง LINQ อาจเพิ่ม LP แบบใหม่ๆ ขึ้นอีกได้ กรอบล่างสุดคือแหล่งข้อมูลที่ใช้ทำคิวรี (Data Source ย่อ DS) โดย DS แต่ละแบบจะสัมพันธ์กับ LP แต่ละตัว

โปรดทราบว่าส่วน LP ไม่ใช่โปรแกรมที่แยกต่างหากหรือปลั๊กอิน แต่เป็น นวัตกรรมที่ถูกผนวกไว้กับภาษาเขียน C# 3.0เลย ที่เป็นไปได้เช่นนั้นเพราะ NETFX และภาษา C# ถูกดัดแปลงต่อเติมเพื่อให้รองรับ LINQ ได้ดังจะอธิบายรายละเอียดในหัวข้อถัดไป

เนื่องจาก DS แบบ RDBMS, DataSet และ ADO.NET Entity Framework ล้วนสัมพันธ์กับฐานข้อมูลดังนั้นเราจึงอาจจัด LP แบบ LINQ to SQL, LINQ to DataSet และ LINQ to Entities ไว้เป็นกลุ่มเดียวกันได้อย่างที่เห็นในภาพ 1-8

ภาพ 1-7: สถาปัตยกรรม LINQ ที่ประกอบด้วยส่วนหลักสี่ส่วนคือภาษาโปรแกรม ส่วนเพิ่มขยายหรือเปลี่ยนแปลงภาษาเพื่อให้ใช้งาน LINQ ได้ ส่วนตัวให้บริการ LINQ และแหล่งข้อมูล

ภาพ 1-8: เราอาจจัด LP แบบ LINQ to SQL, LINQ to DataSet และ LINQ to Entities ไว้เป็นกลุ่มเดียวกันได้

ความเปลี่ยนแปลงในภาษา C#
การจะทำให้ภาษา C# ใช้งาน LINQ ได้ ฮาเยสเบิร์ก จำเป็นต้องเสริมเพิ่มสิ่งจำเป็นให้แก่ NETFX และภาษา C# การเพิ่มที่ว่านี้ไม่ใช่เป็นแค่เพียง “วากยสัมพันธ์แช่อิ่ม” (Syntactic sugar หมายถึงวากยสัมพันธ์ที่ไม่ได้เพิ่มความสามารถให้ภาษา แต่มีไว้เพื่อให้เขียนโค้ดได้สะดวกหรือสง่างามขึ้น) เพื่อให้ท่านคิวรีฐานข้อมูลในภาษา C# ได้สะดวกขึ้นเท่านั้น แต่เป็นการเพิ่มเติมที่ทำให้ท่านสามารถเขียน “โปรแกรมเชิงเจตจำนง” (Declarative Programming ย่อ DP) ได้

สาเหตุที่ต้องยุ่งเกี่ยวกับ DP เพราะภาษาเพื่อการคิวรีข้อมูลในฐานข้อมูลสัมพันธ์ที่นักเขียนโค้ดคุ้นเคยที่สุดคือภาษา SQL เป็นภาษาแบบ DP ซึ่งเน้นการระบุว่าต้องการผลลัพธ์อย่างไร มีหลักการคิดแตกต่างจากภาษา C# ที่เป็นภาษาเชิงกำหนด (Imperative Programming ย่อ IP) ซึ่งเน้นการระบุว่าต้องการให้ดำเนินการอย่างไร

ในชั้นแรกส่วน DP ที่ถูกเพิ่มเข้าใน C# 3.0 มีเจตนาให้ใช้คิวรีข้อมูลเท่านั้น แต่ภายหลังแนวคิดนี้คลี่คลายออกครอบคลุมส่วนที่ไม่ใช่คิวรีด้วย ดังนั้นใน C# 3.0 นอกจากท่านจะสามารถเขียนโปรแกรมตามลัทธิ IP อย่างที่เคยปฏิบัติมาแต่เดิมแล้วท่านยังอาจเขียนโปรแกรมตามลัทธิ DP ได้อีกด้วย

ต่อไปลองมาดูตัวอย่างสิ่งที่เพิ่มขึ้นในภาษา C# เพื่อให้คิวรีข้อมูลได้โดยใช้ LINQ สมมุติว่าท่านได้รับโจทย์ดังนี้ “จงคิวรีข้อมูลในตาราง Products ในฐานข้อมูล AdventureWork2008 เฉพาะแถวที่รหัสสินค้ามากกว่า 2 และชื่อสินค้านำหน้าด้วย A จากนั้นนำผลลัพธ์ที่ได้ไปใส่ในโครงสร้างแบบ XML ในหน่วยความจำ” โจทย์แบบนี้หากไม่ใช้ LINQ ท่านจะต้องเขียนโค้ดโดยใช้เทคโนโลยีสองอย่างผสมกัน คือใช้ ADO.NET เพื่อคิวรีฐานข้อมูล และใช้เนมสเปส System.Xml ของ NETFX เพื่อจัดการ XML แต่ถ้าใช้ LINQ โค้ดจะเป็นอย่างที่เห็นในภาพ 1-9

โค้ดในภาพ 1-9 บรรทัดที่ 13 ถึง 20 ทำหน้าที่คิวรีข้อมูลในตาราง Products ในฐานข้อมูล AdventureWork2008 เฉพาะแถวที่รหัสสินค้ามากกว่า 2 และชื่อสินค้านำหน้าด้วย A บรรทัดที่ 21 ถึง 29 ทำหน้าที่นำผลลัพธ์ไปใส่ในโครงสร้างแบบ XML ในหน่วยความจำ สิ่งที่เพิ่มขึ้นในภาษา C# 3.0 คือส่วน QE ในบรรทัดที่ 16 ถึง 20 จะเห็นว่ามีคำสั่ง from, where, orderby และ select หากนำโค้ดนี้คอมไพล์ใน C# 2.0 ท่านย่อมจะได้รับข้อความแจ้งความผิดพลาดเป็นจำนวนมาก

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

ภาพ 1-9: โค้ดภาษา C# ใช้งาน LINQ เพื่อทำงานตามโจทย์ว่าจงคิวรีข้อมูลในตาราง Products ในฐานข้อมูล AdventureWork2008 เฉพาะแถวที่รหัสสินค้ามากกว่า 2 และชื่อสินค้านำหน้าด้วย A จากนั้นนำผลลัพธ์ที่ได้ไปใส่ในโครงสร้างแบบ XML ในหน่วยความจำ

สาเหตุที่ต้อง LINQ
จากตัวอย่างในหัวข้อที่ผ่านมาท่านอาจนึกอัศจรรย์ใจว่าเพราะเหตุใดเพียงแค่การคิวรีตารางแล้วจับผลลัพธ์มาใส่ XML ไมโครซอฟต์ถึงกับต้องดิ้นรนประดิษฐ์เทคโนโลยีใหม่อย่าง LINQ หรือทำไมหนังสือเล่มนี้ถึงมีเนื้อหายืดยาวมากนัก เพราะดูท่าว่า LINQ คงไม่มีสติอะไร หากท่านคิดเช่นนั้นโปรดอ่านหัวข้อนี้ หากท่านไม่ติดใจจะอ่านข้ามหัวข้อนี้ไปก็ยังได้ ในหัวข้อนี้ผู้เขียนจะอธิบายว่าการเชื่อมต่อกับแหล่งข้อมูลด้วยวิธีเก่ามีปัญหาอย่างไร และ LINQ เป็นทางออกของปัญหาอย่างไร

ปัญหาของ ADO.NET ก่อนหน้ามี LINQ ท่านจะใช้ ADO.NET เพื่อติดต่อกับฐานข้อมูล แท้จริง ADO.NET เป็นเพียงไลบรารีพื้นฐานของดอตเน็ต (.NET Framework Class Library ย่อ FCL) คือเป็นชุด API อันประกอบด้วยคลาสต่างๆ เช่น SqlConnection, SqlCommand, SqlReader, DataSet และ DataTable ฯลฯ ปัญหาของการใช้คลาสเหล่านี้คือท่านจะต้องอ้างถึงตาราง คอลัมน์ และแถวข้อมูลโดยตรง และปรกติในฐานข้อมูลจะมีตารางและคอลัมน์จำนวนมาก การดึงข้อมูลออกจากตารางมาใส่ในหน่วยความจำและการใส่ข้อมูลที่แก้ไขแล้วกลับคืนเข้าไปในตาราง ท่านต้องเขียนรายการคอลัมน์ยืดยาว มีการประเมินว่าทีมนักพัฒนาเสียเวลาไปกับกิจกรรมเหล่านี้คิดเป็นร้อยละ 30 ถึง 40 ของเวลาทั้งโครงการ

ปัญหาของการใช้ ADO.NET ไม่ได้หยุดอยู่เพียงเรื่องประสิทธิภาพในการพัฒนา แต่ยังลามไปถึงคุณภาพของงานด้วย บ่อยครั้งที่นักเขียนโค้ดเผอเรอกำหนดชนิดข้อมูลผิดต้องไล่หาบักอย่างยากลำบาก บางครั้งอาจไม่พบความผิดปรกตินี้จนกว่าจะใช้งานจริงไปสักพัก

 ภาพ 1-10 แสดงโค้ดที่ใช้ ADO.NET ติดต่อฐานข้อมูล AdventureWork2008 เพื่อคิวรีตาราง Products ไล่เรียงข้อจำกัดต่างๆ ได้ดังนี้

•    บรรทัดที่ 11 ถึง 13 โค้ดกำหนดการเชื่อมต่ออยู่ในสภาพสตริง ตัวแปลภาษาจึงไม่รับรู้หากกำหนดค่าผิด
•    บรรทัดที่ 17 และ 18 เป็นคิวรีที่อยู่ในสภาพสตริง ตัวแปลภาษาจึงไม่รับรู้หากเขียนคิวรีผิด
•    บรรทัดที่ 25 และ 26 ผู้เขียนโค้ดไม่รู้ว่าข้อมูลที่รับมาเป็นไทป์อะไรเพราะส่วนอินเทลลิเซนส์ไม่สามารถแสดงคำแนะนำใดๆ ได้
•    หากเปลี่ยนดาต้าเบสเซอฟเวอร์ (เช่นเปลี่ยนจากเซอฟเวอร์ที่ใช้ในการทดสอบไปเป็นเซอฟเวอร์ที่ใช้งานจริง) โค้ดนี้จะเออเรอร์ทันที นอกเสียจากว่าจะแก้ไขส่วนกำหนดการเชื่อมต่อเสียก่อน

 ภาพ 1-11 แสดงโค้ดที่ใช้ LINQ ติดต่อฐานข้อมูล AdventureWork2008 เพื่อคิวรีตาราง Products ไล่เรียงการแก้ปัญหาต่างๆ ได้ดังนี้

•    บรรทัดที่ 40-14 การกำหนดการเชื่อมต่ออยู่ในสภาพออพเจ็กต์ที่ตัวแปรภาษารับรู้
•    บรรทัดที่ 43-44 คิวรีทำในภาษา C# โดยตรง ตัวแปรภาษาตรวจสอบวากยสัมพันธ์ได้
•    บรรทัด 49-30 เนื่องจาก r เป็นออพเจ็กต์ ส่วน ProductID และ Name มีภาวะเป็นพร็อพเพอร์ตีสมาชิกของ r  อินเทลลิเซนส์จึงสามารถแสดงคำแนะนำได้
•    หากเปลี่ยนดาต้าเบสเซอฟเวอร์ (เช่นเปลี่ยนจากเซอฟเวอร์ที่ใช้ในการทดสอบไปเป็นเซอฟเวอร์ที่ใช้งานจริง) ท่านไม่ต้องแก้ไขอะไรในโค้ดนี้เลย เพียงแต่เปลี่ยน O/RM ใหม่

 

ภาพ 1-10 โค้ดที่ใช้ ADO.NET ติดต่อฐานข้อมูล AdventureWork2008 เพื่อคิวรีตาราง Products

ภาพ 1-11 โค้ดที่ใช้ LINQ ติดต่อฐานข้อมูล AdventureWork2008 เพื่อคิวรีตาราง Products

 

กรุณาติดตามตอนต่อไป

One Response to ทำความรู้จัก LINQ [ตอน2]

  1. Absulation says:

    อ.ครับ หนังสือจะออกเมื่อไหร่ครับ รออุดหนุนอยู่ครับ

ใส่ความเห็น

This site uses Akismet to reduce spam. Learn how your comment data is processed.