1. การติดตั้งเครื่องมือ ent

เพื่อที่จะติดตั้งเครื่องมือสร้างโค้ด ent คุณต้องทำตามขั้นตอนเหล่านี้:

ก่อนอื่นให้แน่ใจว่าระบบของคุณได้ติดตั้ง Go language environment แล้ว จากนั้นให้รันคำสั่งต่อไปนี้เพื่อรับเครื่องมือ ent:

go get -d entgo.io/ent/cmd/ent

คำสั่งนี้จะดาวน์โหลดโค้ดสำหรับเครื่องมือ ent แต่จะไม่คอมไพล์และติดตั้งในทันที หากคุณต้องการที่จะติดตั้ง ent ไปยังไดเร็กทอรี $GOPATH/bin เพื่อให้คุณใช้งานได้ทุกที่ คุณยังต้องทำการรันคำสั่งต่อไปนี้ด้วย:

go install entgo.io/ent/cmd/ent

เมื่อการติดตั้งเสร็จสิ้นแล้ว คุณสามารถตรวจสอบว่าเครื่องมือ ent ได้ถูกติดตั้งอย่างถูกต้องหรือไม่ และดูคำสั่งและคำแนะนำที่สามารถใช้ได้โดยการรัน ent -h.

2. การเริ่มต้นสร้าง Schema

2.1 การเริ่มต้น Template โดยใช้ ent init

การสร้างไฟล์ Schema ใหม่คือขั้นตอนแรกในการเริ่มใช้ ent สำหรับการสร้างโค้ด คุณสามารถเริ่มต้น Template ของ schema โดยการรันคำสั่งต่อไปนี้:

go run -mod=mod entgo.io/ent/cmd/ent new User Pet

คำสั่งนี้จะสร้างไฟล์ schema ใหม่สองไฟล์: user.go และ pet.go และวางไว้ในไดเร็กทอรี ent/schema หากรายการ ent ไม่มีอยู่ คำสั่งนี้ยังจะสร้างอัตโนมัติด้วย

การรันคำสั่ง ent init ในไดเร็กทอรีหลักของโปรเจคเป็นการปฏิบัติที่ดี เนื่องจากมันช่วยในการรักษาโครงสร้างและความชัดเจนของไดเร็กทอรีของโปรเจค

2.2 โครงสร้างไฟล์ Schema

ในไดเร็กทอรี ent/schema แต่ละ schema สอดคล้องกับไฟล์ที่มีภาษา Go ไฟล์ schema คือที่ที่คุณกำหนดโมเดลฐานข้อมูล ซึ่งรวมถึงฟิลด์และเส้น (ความสัมพันธ์)

ตัวอย่างเช่น ในไฟล์ user.go คุณอาจกำหนดโมเดลผู้ใช้รวมถึงฟิลด์เช่น ชื่อผู้ใช้และอายุ และกำหนดความสัมพันธ์ระหว่างผู้ใช้และสัตว์เลี้ยง อย่างเดียวกันในไฟล์ pet.go คุณจะกำหนดโมเดลของสัตว์เลี้ยงและฟิลด์ที่เกี่ยวข้อง เช่น ชื่อของสัตว์เลี้ยง ชนิด และความสัมพันธ์ระหว่างสัตว์เลี้ยงกับผู้ใช้

ไฟล์เหล่านี้จะถูกใช้โดยเครื่องมือ ent เพื่อสร้างโค้ด Go ที่สอดคล้องกับฐานข้อมูล รวมถึงโค้ดไคลเอนต์สำหรับการปฏิบัติการฐานข้อมูลและการปฏิบัติ CRUD (สร้าง อ่าน ปรับปรุง ลบ)

// ent/schema/user.go
package schema

import (
    "entgo.io/ent"
    "entgo.io/ent/schema/field"
)

// User กำหนด schema สำหรับ entity ของ User
type User struct {
    ent.Schema
}

// วิธี Fields ใช้เพื่อกำหนดฟิลด์ของ entity
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("name").Unique(),
        field.Int("age").Positive(),
    }
}

// วิธี Edges ใช้เพื่อกำหนดความสัมพันธ์ของ entity
func (User) Edges() []ent.Edge {
    // ความสัมพันธ์จะถูกอธิบายอย่างละเอียดมากขึ้นในส่วนถัดไป
}

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

3.1 การรันการสร้างโค้ด

การรัน ent generate เพื่อสร้างโค้ดเป็นขั้นตอนที่สำคัญในเฟรมเวิร์ก ent ด้วยคำสั่งนี้ ent จะสร้างไฟล์โค้ด Go ที่สอดคล้องกับ schema ที่กำหนด เพื่อให้ง่ายต่อการพัฒนาต่อไป คำสั่งสำหรับการรันการสร้างโค้ดก็มีความเรียบง่าย:

go generate ./ent

คำสั่งข้างต้นจำเป็นต้องรันในไดเร็กทอรีหลักของโปรเจค เมื่อทำการเรียกใช้ go generate มันจะค้นหาไฟล์ Go ทุกไฟล์ที่มี annotation ที่เฉพาะเจาะจง และทำการรันคำสั่งที่ระบุไว้ใน annotation ในตัวอย่างของเรา คำสั่งนี้ระบุการสร้างโค้ดสำหรับ ent

โปรด ensure ว่าการเริ่มต้น schema และการเพิ่มฟิลด์ที่จำเป็นได้เสร็จสิ้นก่อนการที่จะทำการรัน อย่างเดียวจึงจะเห็นโค้ดที่สร้างไว้ทั้งหมดที่จำเป็น

3.2 เข้าใจส่วนประกอบของรหัสที่ถูกสร้างขึ้น

ส่วนประกอบของรหัสที่ถูกสร้างขึ้นประกอบด้วยหลายส่วน แต่ละส่วนมีหน้าที่แตกต่างกันดังนี้:

  • Client และ Tx objects: ใช้สำหรับการโต้ตอบกับกราฟข้อมูล ส่วน Client ให้เมทอดสำหรับสร้างการทำธุรกรรม (Tx) หรือดำเนินการกับฐานข้อมูลโดยตรง
  • CRUD builders: สำหรับแต่ละประเภทของสกีม่า มันสร้างตัวสร้างสำหรับการสร้าง อ่าน อัปเดต และลบ ซึ่งทำให้ตรรกะการดำเนินการขององค์กรที่เกี่ยวข้องเรียบง่ายขึ้น
  • Entity object (Go struct): มันสร้าง Go structs ที่เกี่ยวข้องสำหรับแต่ละประเภทในสกีม่า โดยแมพ structs เหล่านี้ไปยังตารางในฐานข้อมูล
  • Constants และ predicates package: ประกอบด้วยค่าคงที่และ predicates สำหรับการโต้ตอบกับตัวสร้าง
  • Migrate package: เป็นแพ็คเกจสำหรับการโยกย้ายฐานข้อมูลที่เหมาะสำหรับ dialects ของ SQL
  • Hook package: ให้ความสามารถในการเพิ่ม middleware การเปลี่ยนแปลง ทำให้สามารถดำเนินตรรกะโลจิกที่กำหนดเองก่อนหรือหลังการสร้าง การอัปเดต หรือการลบ entities

การตรวจสอบรหัสที่ถูกสร้างขึ้นจะทำให้คุณเข้าใจลึกลงถึงวิธีที่เฟรมเวิร์ก ent ทำการอัตโนมัติรหัสการเข้าถึงข้อมูลสำหรับสกีม่าของคุณ

4. ตัวเลือกการสร้างรหัส

คำสั่ง ent generate รองรับตัวเลือกต่าง ๆ เพื่อปรับแต่งกระบวนการการสร้างรหัสได้ คุณสามารถสอบถามทุกตัวเลือกการสร้างที่รองรับได้ผ่านคำสั่งต่อไปนี้:

ent generate -h

นี่คือตัวเลือกบางอย่างที่ใช้บ่อย:

  • --feature strings: ขยายการสร้างรหัสโดยการเพิ่มฟังก์ชันพิเศษ
  • --header string: แทนที่ไฟล์ส่วนหัวของการสร้างรหัส
  • --storage string: ระบุ storage driver ที่รองรับในกระบวนการสร้างรหัส ซึ่งมีค่าเริ่มต้นเป็น "sql"
  • --target string: ระบุไดเรกทอรี่เป้าหมายสำหรับการสร้างรหัส
  • --template strings: ดำเนินการ Go templates เพิ่มเติม รองรับไฟล์ ไดเรกทอรี และรูปแบบการระบุพาธที่ใช้ * เช่น: --template file="path/to/file.tmpl"

ตัวเลือกเหล่านี้ช่วยให้นักพัฒนาสามารถปรับแต่งกระบวนการการสร้างรหัสตามความต้องการและความชอบของตนได้

5. การกำหนดตัวเลือกการเก็บข้อมูล

ent รองรับการสร้างรหัสที่เกี่ยวข้องกับ dialects ของทั้ง SQL และ Gremlin โดยค่าเริ่มต้นคือ dialect ของ SQL หากโปรเจคต้องการเชื่อมต่อกับฐานข้อมูลแบบ Gremlin ตัวเลือกของ dialect ฐานข้อมูลที่เกี่ยวข้องต้องการจัดกำหนด ตัวอย่างการระบุตัวเลือกการจัดเก็บดังต่อไปนี้:

ent generate --storage gremlin ./ent/schema

คำสั่งด้านบนนี้หมายความว่า ent จะใช้ dialect ของ Gremlin เมื่อสร้างรหัส นี้ทำให้รหัสที่สร้างไว้เป็นไปตามความต้องการของฐานข้อมูล Gremlin และทำให้เหมาะกับฐานข้อมูลกราฟแบบเฉพาะ

6. การใช้งานขั้นสูง: แพ็คเกจ entc

6.1 การใช้งานของ entc เป็นแพ็คเกจในโปรเจค

entc เป็นแพ็คเกจหลักที่ใช้สำหรับการสร้างรหัสในเฟรมเวิร์ก ent นอกจากเครื่องมือบรรทัดคำสั่ง entc ยังสามารถรวมเข้ากับโปรเจคเป็นแพ็คเกจ ทำให้นักพัฒนาสามารถควบคุม และปรับแต่งกระบวนการการสร้างรหัสภายในโค้ดได้เอง

เพื่อใช้ entc เป็นแพ็คเกจในโปรเจค คุณต้องสร้างไฟล์ชื่อ entc.go และเพิ่มเนื้อหาต่อไปนี้ลงในไฟล์:

// +build ignore

package main

import (
    "log"
    "entgo.io/ent/entc"
    "entgo.io/ent/entc/gen"
)

func main() {
    if err := entc.Generate("./schema", &gen.Config{}); err != nil {
        log.Fatal("running ent codegen:", err)
    }
}

เมื่อใช้วิธีนี้ คุณสามารถแก้ไข gen.Config struct ภายในฟังก์ชัน main เพื่อปรับใช้ตัวเลือกการกำหนดต่าง ๆ โดยการเรียกใช้ฟังก์ชัน entc.Generate ตามที่ต้องการ ทำให้คุณสามารถควบคุมกระบวนการการสร้างรหัสได้อย่างยืดหยุ่น

6.2 การกำหนดคอนฟิกเพิ่มเติมของ entc

entc มีตัวเลือกการกำหนดคอนฟิกอย่างมากที่ทำให้นักพัฒนาสามารถกำหนดรหัสที่ถูกสร้างได้อย่างเทรคเจอร์ ตัวอย่างเช่น สามารถกำหนดฮุกที่กำหนดได้เองเพื่อตรวจสอบหรือปรับเปลี่ยนรหัสที่ได้สร้าง และสามารถฉีดฝอยขึ้นโดยการใช้การฉีดฝอยขึ้นโดยใช้การฉีดฝอยเข้ามาภายนอก

ตัวอย่างต่อไปนี้สาธิตถึงวิธีการกำหนดฮุกที่กำหนดเองสำหรับฟังก์ชัน entc.Generate:

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Hooks: []gen.Hook{
            HookFunction,
        },
    })
    if err != nil {
        log.Fatalf("running ent codegen: %v", err)
    }
}

// HookFunction เป็นฟังก์ชันฮุกที่กำหนดเอง
func HookFunction(next gen.Generator) gen.Generator {
    return gen.GenerateFunc(func(g *gen.Graph) error {
        // สามารถจัดการโหมดกราฟที่แทนโดย g ได้ที่นี่
        // ตัวอย่างเช่น การตรวจสอบความถูกต้องของฟิลด์หรือปรับโครงสร้าง
        return next.Generate(g)
    })
}

นอกจากนี้สามารถเพิ่มฝอยขึ้นจากภายนอกได้โดยใช้ entc.Dependency:

func main() {
    opts := []entc.Option{
        entc.Dependency(
            entc.DependencyType(&http.Client{}),
        ),
        entc.Dependency(
            entc.DependencyName("Writer"),
            entc.DependencyTypeInfo(&field.TypeInfo{
                Ident:   "io.Writer",
                PkgPath: "io",
            }),
        ),
    }
    if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
        log.Fatalf("running ent codegen: %v", err)
    }
}

ในตัวอย่างนี้ เราฉีด http.Client และ io.Writer เข้าไปเป็นฝอยขึ้นในวัตถุที่สร้างขึ้นทั้งนั้น

7. ผลลัพธ์ของการอธิบายสกีม่า

ในกรอบของ ent คำสั่ง ent describe สามารถใช้สำหรับการออกแบบสกีม่าในรูปแบบกราฟได้ นี้สามารถช่วยให้นักพัฒนาเข้าใจรายละเอียดของส่วนประกอบและความสัมพันธ์ที่มีอยู่ได้อย่างรวดเร็ว

ดำเนินการคำสั่งต่อไปนี้เพื่อรับรายละเอียดของสกีม่า:

go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema

คำสั่งข้างต้นจะส่งออกตารางที่คล้ายกับตารางต่อไปนี้ แสดงข้อมูลเช่น ฟิลด์ ประเภท ความเป็นเอกลักษณ์ ทางเลือกได้อย่างไรในแต่ละส่วนประกอบ:

ผู้ใช้:
    +-------+---------+--------+-----------+ ...
    | ฟิลด์ |  ประเภท   | ยูนิค | ตัวเลือก  | ...
    +-------+---------+--------+-----------+ ...
    | id    | int     | เท็จ  | เท็จ     | ...
    | ชื่อ  | หนังสือสตริง  | เป็นไปตาม   | เท็จ     | ...
    +-------+---------+--------+-----------+ ...
    +-------+--------+---------+-----------+ ...
    | เส้น |  ประเภท  | กลับหลัง | ความสัมพันธ์  | ...
    +-------+--------+---------+-----------+ ...
    | สัตว์เลี้ยง  | สัตว์เลี้ยง   | เท็จ   | O2M       | ...
    +-------+--------+---------+-----------+ ...

8. ฮุคส์สร้างรหัส

8.1 แนวคิดของฮุค

ฮุคเป็น ฟังก์ชัน middleware ที่สามารถแทรกลงในกระบวนการการสร้างรหัสของ ent ที่อนุญาตให้มีตรรกะการดำเนินการที่กำหนดเองก่อนและหลังจากการสร้างรหัส ฮุคสามารถใช้เพื่อจัดการต้นไม้สัณฑ์สำเร็จรูป (AST) ของรหัสที่สร้าง เพิ่มการตรวจสอบ หรือเพิ่มคำสั่งรหัสเพิ่มเติม

8.2 ตัวอย่างของการใช้ฮุค

นี่คือตัวอย่างของการใช้ฮุคเพื่อให้แน่ใจว่าทุกฟิลด์มีแท็กโครงสร้างบางประเภท (เช่น json):

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Hooks: []gen.Hook{
            EnsureStructTag("json"),
        },
    })
    if err != nil {
        log.Fatalf("running ent codegen: %v", err)
    }
}

// ห้าม EnsureStructTag นี้ให้แน่ใจว่าทุกฟิลด์ในกราฟมีแท็กโครงสร้างรูปแบบเฉพาะ
func EnsureStructTag(name string) gen.Hook {
    return func(next gen.Generator) gen.Generator {
        return gen.GenerateFunc(func(g *gen.Graph) error {
            for _, node := range g.Nodes {
                for _, field := range node.Fields {
                    tag := reflect.StructTag(field.StructTag)
                    if _, ok := tag.Lookup(name); !ok {
                        return fmt.Errorf("ยังไม่มีแท็กโครงสร้าง %q สำหรับฟิลด์ %s.%s", name, node.Name, field.Name)
                    }
                }
            }
            return next.Generate(g)
        })
    }
}

ในตัวอย่างนี้ ก่อนที่จะสร้างรหัส ฟังก์ชัน EnsureStructTag จะตรวจสอบทุกฟิลด์สำหรับแท็ก json หากฟิลด์ใดที่ไม่มีแท็กนี้การสร้างรหัสจะสิ้นสุดลงและส่งคืนข้อผิดพลาดนี้ เป็นวิธีที่มีประสิทธิภาพที่ในการรักษารูปแบบและความสม่ำเสมอของโค้ด