Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

Query Builder: สร้าง Query อย่างยืดหยุ่นด้วย ORM

บทความนี้แนะนำ Query Builder ซึ่งเป็นเครื่องมือใน ORM ที่ช่วยสร้าง SQL Query แบบ Dynamic โดยไม่ต้องเขียน SQL เองโดยตรง ทำให้โค้ดอ่านง่ายขึ้น ป้องกัน SQL Injecti...

Query Builder: สร้าง Query อย่างยืดหยุ่นด้วย ORM

ในบทความก่อนหน้านี้ เราได้เรียนรู้เกี่ยวกับการจัดการความสัมพันธ์ระหว่าง Entity ต่างๆ ในฐานข้อมูลด้วย ORM (Doctrine) ซึ่งเป็นวิธีที่ช่วยให้เราไม่ต้องเขียน SQL เองโดยตรง แต่ในบางครั้งความต้องการในการดึงข้อมูลของเราอาจซับซ้อนกว่าการใช้ Repository Method ที่ ORM เตรียมไว้ให้ ในสถานการณ์เช่นนี้ Query Builder จะเข้ามาช่วยให้เราสร้าง Query ที่ยืดหยุ่นและปรับแต่งได้ตามต้องการ

Query Builder คืออะไร?

Query Builder คือเครื่องมือที่ ORM เตรียมไว้ให้เพื่อช่วยในการสร้าง SQL Query แบบ Dynamic (เปลี่ยนแปลงได้ตามเงื่อนไข) โดยไม่ต้องเขียน SQL เองโดยตรง มันเป็น API ที่ช่วยให้เราสามารถสร้าง Query ได้ทีละส่วน โดยการเพิ่มเงื่อนไขต่างๆ เช่น WHERE, ORDER BY, JOIN, และอื่นๆ เข้าไปใน Query ทีละขั้นตอน

เหตุผลเชิงออกแบบ (Design Trade-offs): ทำไมต้องมี Query Builder ในเมื่อเราเขียน SQL เองได้? คำตอบคือ Query Builder ช่วยลดความผิดพลาดที่อาจเกิดขึ้นจากการเขียน SQL เองโดยตรง (เช่น SQL Injection) และทำให้โค้ดของเราอ่านง่ายขึ้น บำรุงรักษาง่ายขึ้น และสามารถนำไปใช้ซ้ำได้ง่ายขึ้น นอกจากนี้ Query Builder ยังช่วยให้เราไม่ต้องกังวลเกี่ยวกับความแตกต่างของ Syntax (ไวยากรณ์) SQL ระหว่างฐานข้อมูลแต่ละประเภท เพราะ ORM จะจัดการแปลง Query ที่เราสร้างขึ้นให้เป็น SQL ที่ถูกต้องสำหรับฐานข้อมูลที่เราใช้งานอยู่

การใช้งาน Query Builder

การใช้งาน Query Builder ใน Doctrine (หรือ ORM อื่นๆ) มักจะเริ่มต้นด้วยการเรียกใช้ createQueryBuilder() จาก Repository ของ Entity ที่เราต้องการดึงข้อมูล ตัวอย่างเช่น ถ้าเราต้องการดึงข้อมูลจาก Entity Product เราสามารถทำได้ดังนี้:

// สมมติว่าเรามี ProductRepository ที่ inject เข้ามาใน Class นี้แล้ว

$queryBuilder = $this->productRepository->createQueryBuilder('p');
// 'p' คือ alias (ชื่อแทน) สำหรับ Entity Product ใน Query นี้

หลังจากได้ $queryBuilder มาแล้ว เราสามารถเพิ่มเงื่อนไขต่างๆ เข้าไปใน Query ได้ ตัวอย่างเช่น:

การ Filter ข้อมูล

การ Filter ข้อมูลคือการกำหนดเงื่อนไข WHERE ใน SQL Query เพื่อเลือกเฉพาะข้อมูลที่เราต้องการ Query Builder มีวิธีการ Filter ข้อมูลหลายแบบ เช่น

  • เท่ากับ (Equals): ใช้ setParameter() และ where()
  • ไม่เท่ากับ (Not Equals): ใช้ setParameter() และ where() ร่วมกับ != หรือ <>
  • มากกว่า (Greater Than): ใช้ setParameter() และ where() ร่วมกับ >
  • น้อยกว่า (Less Than): ใช้ setParameter() และ where() ร่วมกับ <
  • ระหว่าง (Between): ใช้ setParameter() และ where() ร่วมกับ BETWEEN
  • อยู่ใน (In): ใช้ setParameter() และ where() ร่วมกับ IN
  • คล้าย (Like): ใช้ setParameter() และ where() ร่วมกับ LIKE

ตัวอย่างการ Filter ข้อมูลเพื่อดึง Product ที่มีราคามากกว่า 1000 บาท:

$queryBuilder = $this->productRepository->createQueryBuilder('p')
    ->where('p.price > :price') // กำหนดเงื่อนไข WHERE price > :price
    ->setParameter('price', 1000); // กำหนดค่าให้ parameter 'price' คือ 1000

$products = $queryBuilder->getQuery()->getResult(); // execute query และ return ผลลัพธ์

อธิบายเพิ่มเติม:

  • 'p.price > :price' คือเงื่อนไขที่เราต้องการใช้ โดย p คือ alias ของ Entity Product และ price คือ attribute ของ Entity
  • ':price' คือ Parameter ที่เราใช้เพื่อป้องกัน SQL Injection และทำให้โค้ดของเราอ่านง่ายขึ้น
  • setParameter('price', 1000) คือการกำหนดค่าให้ Parameter price เป็น 1000
  • getQuery() คือการสร้าง Query Object จาก Query Builder
  • getResult() คือการ execute Query และ return ผลลัพธ์เป็น Array ของ Entity Product

การ Sort ข้อมูล

การ Sort ข้อมูลคือการเรียงลำดับข้อมูลตามเงื่อนไขที่เรากำหนด Query Builder มี Method orderBy() สำหรับเรียงลำดับข้อมูล

ตัวอย่างการ Sort ข้อมูลเพื่อเรียง Product ตามราคาจากมากไปน้อย:

$queryBuilder = $this->productRepository->createQueryBuilder('p')
    ->orderBy('p.price', 'DESC'); // เรียงตาม price จากมากไปน้อย (Descending)

$products = $queryBuilder->getQuery()->getResult();

อธิบายเพิ่มเติม:

  • orderBy('p.price', 'DESC') คือการเรียงลำดับข้อมูลตาม attribute price ของ Entity Product จากมากไปน้อย (DESC ย่อมาจาก Descending) ถ้าเราต้องการเรียงจากน้อยไปมาก เราสามารถใช้ ASC (Ascending) แทนได้

การ Join Table

ในบทก่อนหน้านี้ เราได้เรียนรู้เกี่ยวกับการจัดการความสัมพันธ์ระหว่าง Entity ต่างๆ การ Join Table คือการรวมข้อมูลจากหลาย Table ที่มีความสัมพันธ์กัน Query Builder มี Method join(), leftJoin(), และ rightJoin() สำหรับ Join Table

ตัวอย่างการ Join Table เพื่อดึง Product และ Category ของ Product นั้น:

$queryBuilder = $this->productRepository->createQueryBuilder('p')
    ->join('p.category', 'c') // Join ตาราง Product กับ Category โดยใช้ความสัมพันธ์ใน Entity Product (p.category)
    ->where('c.name = :categoryName') // Filter โดย category name
    ->setParameter('categoryName', 'Electronics');

$products = $queryBuilder->getQuery()->getResult();

อธิบายเพิ่มเติม:

  • join('p.category', 'c') คือการ Join Table Product กับ Category โดยใช้ความสัมพันธ์ category ที่เราได้กำหนดไว้ใน Entity Product (p.category) และกำหนด Alias ให้ Table Category เป็น c
  • where('c.name = :categoryName') คือการ Filter ข้อมูลโดยเลือกเฉพาะ Product ที่มี Category Name เท่ากับ :categoryName
  • setParameter('categoryName', 'Electronics') คือการกำหนดค่าให้ Parameter categoryName เป็น Electronics

แนวปฏิบัติที่ดี (Best Practices):

  • ใช้ Parameter: ควรใช้ Parameter เสมอเมื่อต้องการใส่ค่าเข้าไปใน Query เพื่อป้องกัน SQL Injection
  • Alias ที่สื่อความหมาย: ตั้ง Alias ให้ Entity และ Table ให้สื่อความหมาย เพื่อให้โค้ดอ่านง่ายขึ้น
  • แบ่ง Query ที่ซับซ้อนออกเป็นส่วนๆ: ถ้า Query ซับซ้อนมาก ควรแบ่งออกเป็นส่วนๆ เพื่อให้ง่ายต่อการทำความเข้าใจและบำรุงรักษา

สรุป

Query Builder เป็นเครื่องมือที่มีประโยชน์มากในการสร้าง SQL Query ที่ยืดหยุ่นและปรับแต่งได้ตามต้องการใน ORM ช่วยให้เราไม่ต้องเขียน SQL เองโดยตรง ลดความผิดพลาด และทำให้โค้ดของเราอ่านง่ายขึ้น บำรุงรักษาง่ายขึ้น และสามารถนำไปใช้ซ้ำได้ง่ายขึ้น การเข้าใจและใช้งาน Query Builder ได้อย่างมีประสิทธิภาพ จะช่วยให้เราสามารถพัฒนาแอปพลิเคชันที่ซับซ้อนได้อย่างรวดเร็วและมีประสิทธิภาพมากยิ่งขึ้น

ในบทความต่อไป เราจะมาเรียนรู้เกี่ยวกับ Repository Pattern ซึ่งเป็น Pattern ที่ช่วยให้เราจัดการ Data Access Layer ได้อย่างเป็นระบบและมีประสิทธิภาพมากยิ่งขึ้น

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service