1. แนวคิดพื้นฐานของ Entity และ Association
ในเฟรมเวิร์ก ent
องค์กรหมายถึงหน่วยข้อมูลพื้นฐานที่จัดการในฐานข้อมูล ซึ่งโดยทั่วไปมักจะสอดคล้องกับตารางในฐานข้อมูล ฟิลด์ในองค์กรสอดคล้องกับคอลัมน์ในตาราง ในขณะเดียวกันการมีการเชื่อมโยง (เชื่อมต่อ) ระหว่างองค์กรถูกใช้เพื่ออธิบายความสัมพันธ์และความขึ้นอยู่ระหว่างองค์กร การเชื่อมโยงขององค์กรเป็นพื้นฐานสำหรับการสร้างโมเดลข้อมูลที่ซับซ้อน ทำให้เป็นไปได้ที่จะแทนสถานการณ์ที่มีความสัมพันธ์แบบชั้นย่อย เช่น ความสัมพันธ์ระหว่างพ่อแม่และลูก และความสัมพันธ์เจ้าของสิทธิ์
เฟรมเวิร์ก ent
มี APIs ที่หลากหลายที่ให้นักพัฒนาสามารถนิยามและจัดการเชื่อมโยงเหล่านี้ในโครงสร้างขององค์กร ผ่านเชื่อมโยงเหล่านี้ เรารสามารถแสดงออกและดำเนินการกับตรรกะธุรกิจที่ซับซ้อนได้อย่างง่ายดาย
2. ประเภทของการเชื่อมโยงของ Entity ใน ent
2.1 การเชื่อมโยงแบบหนึ่งต่อหนึ่ง (O2O) Association
การเชื่อมโยงแบบหนึ่งต่อหนึ่งหมายถึงความสอดคล้องแบบหนึ่งต่อหนึ่งระหว่างองค์กรสององค์กร ตัวอย่างเช่น ในกรณีของผู้ใช้และบัญชีธนาคาร แต่ละผู้ใช้สามารถมีเพียงหนึ่งบัญชีธนาคาร และแต่ละบัญชีธนาคารก็เป็นของผู้ใช้โดยเดียว ฟังก์ชัน edge.To
และ edge.From
ในเฟรมเวิร์ก ent
ใช้ในการนิยามการเชื่อมโยงเช่นนี้
ก่อนอื่นเราสามารถนิยามการเชื่อมโยงแบบหนึ่งต่อหนึ่งที่ชี้ไปยัง Card
ภายในโครงสร้าง User
ได้เป็นวิธีนี้:
// เชื่อมโยงของ User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("card", Card.Type). // ชี้ไปที่องค์กร Card และกำหนดชื่อเชื่อมโยงเป็น "card"
Unique(), // ฟังก์ชัน Unique รับประกันว่านี่คือการเชื่อมโยงแบบหนึ่งต่อหนึ่ง
}
}
ต่อมา เราจะนิยามการเชื่อมโยงตรงกลับไปที่ User
ภายในโครงสร้าง Card
ต่อไปนี้:
// เชื่อมโยงของ Card.
func (Card) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type). // ชี้กลับไปยัง User จาก Card และกำหนดชื่อเชื่อมโยงเป็น "owner"
Ref("card"). // ฟังก์ชัน Ref ระบุชื่อการเชื่อมโยงตรงกลับที่เหมือนกัน
Unique(), // แสดงถึงผู้ที่ถูกสั่งให้เพื่อให้แน่ใจว่าบัตรหนึ่งสัมพัสวัตถุี
}
}
2.2 การเชื่อมโยงแบบหนึ่งต่อมากกว่าหนึ่ง (O2M) Association
การเชื่อมโยงแบบหนึ่งต่อมากกว่าหนึ่งระบุว่าองค์กรหนึ่งสามารถมีการเชื่อมโยงกับองค์กรอื่นหลายๆ องค์กร แต่องค์กรเหล่านี้สามารถชี้กลับไปที่องคกรที่เดียวกันเท่านั้น ตัวอย่างเช่น ผู้ใช้อาจมีสัตว์เลี้ยงหลายตัว แต่แต่ละสัตว์เลี้ยงก็มีเพียงผู้เจ้าของตัวเดียว
ใน ent
เรายังคงใช้ edge.To
และ edge.From
เพื่อนิยามประเภทการเชื่อมโยงเช่นนี้ ตัวอย่างต่อไปนี้นำเสนอการเชื่อมโยงแบบหนึ่งต่อมากกว่าหนึ่งระหว่างผู้ใช้และสัตว์เลี้ยง:
// เชื่อมโยงของ User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type), // การเชื่อมโยงแบบหนึ่งต่อมากกว่าหนึ่งจากองค์กร User ไปยังองค์กร Pet
}
}
ในองค์กร Pet
เรานิยามการเชื่อมโยงแบบมากต่อหนึ่งกลับไปที่ User
ต่อไปนี้:
// เชื่อมโยงของ Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type). // การเชื่อมโยงแบบมากต่อหนึ่งจาก Pet ไปยัง User
Ref("pets"). // ระบุชื่อการเชื่อมโยงตรงกลับจาก pet ไปยัง owner
Unique(), // รับประกันว่าเจ้าของหนึ่งคนสามารถมีสัตว์เลี้ยงหลายตัว
}
}
2.3 การเชื่อมโยงแบบมากต่อมาก (M2M) Association
การเชื่อมโยงแบบมากต่อมากช่วยให้องค์กรสองประเภทสามารถมีตัวอย่างหลายตัวขององค์กรตัวเอง ตัวอย่างเช่น นักศึกษาสามารถลงทะเบียนเรียนในหลายรายวิชา และรายวิชาก็สามารถมีนักศึกษาตัวอย่างหลายท่านที่ลงทะเบียนเรียนอยู่เช่นเดียวกัน ent
มี APIs ที่เพื่อนุนการเชื่อมโยงแบบมากต่อมากได้:
ในองค์กร Student
เราใช้ edge.To
ในการนิยามการเชื่อมโยงแบบมากต่อมากกับ Course
:
// เชื่อมโยงของ Student.
func (Student) Edges() []ent.Edge {
return []ent.Edge{
edge.To("courses", Course.Type), // นิยามการเชื่อมโยงแบบมากต่อมากจาก Student ไปยัง Course
}
}
ในทำเดียวกันในองค์กร Course
เรานิยามการเชื่อมโยงตรงกลับไปยัง Student
สำหรับความสัมพันธ์แบบมากต่อมากต่อไปนี้:
// เชื่อมโยงของ Course.
func (Course) Edges() []ent.Edge {
return []ent.Edge{
edge.From("students", Student.Type). // นิยามการเชื่อมโยงแบบมากต่อมากจาก Course ไปยัง Student
Ref("courses"), // ระบุชื่อการเชื่อมโยงตรงกลับจาก Course ไปยัง Student
}
}
การเชื่อมโยงเหล่านี้เป็นฐานรากสำคัญของการสร้างโมเดลข้อมูลแอปพลิเคชั่นที่ซับซ้อน และความเข้าใจในวิธีการนิยามและใช้เชื่อมโยงใน ent
เป็นสิ่งสำคัญสำหรับการขยายโมเดลข้อมูลและตรรกะธุรกิจข้อมูลเช่นใด
3. การดำเนินการพื้นฐานสำหรับการเชื่อมโยงของ Entity
ในส่วนนี้จะแสดงวิธีการดำเนินการพื้นฐานโดยใช้ ent
กับความเกี่ยวข้องที่กำหนดไว้ ซึ่งรวมถึงการสร้าง การคิวรี่ และการเดินทางข้าม Entity ที่เกี่ยวข้อง
3.1 การสร้าง Associated Entities
ในขณะที่สร้าง entities คุณสามารถกำหนดความสัมพันธ์ระหว่าง entities พร้อมกัน สำหรับความสัมพันธ์ one-to-many (O2M) และ many-to-many (M2M) คุณสามารถใช้วิธี Add{Edge}
เพื่อเพิ่ม associated entities
ตัวอย่างเช่น หากเรามี user entity และ pet entity ที่มีความสัมพันธ์บางอย่าง โดยที่ผู้ใช้สามารถมีสัตว์เลี้ยงหลายตัว ต่อไปนี้เป็นตัวอย่างของการสร้างผู้ใชมงใหม่และเพิ่มสัตว์เลี้ยงให้กับพวกเขา:
// สร้างผู้ใช้และเพิ่มสัตว์เลี้ยง
func CreateUserWithPets(ctx context.Context, client *ent.Client) (*ent.User, error) {
// สร้างตัวอย่างของสัตว์เลี้ยง
fido := client.Pet.
Create().
SetName("Fido").
SaveX(ctx)
// สร้างตัวอย่างของผู้ใช้และเชื่อมโยงกับสัตว์เลี้ยง
user := client.User.
Create().
SetName("Alice").
AddPets(fido). // ใช้วิธี AddPets เพื่อเชื่อมโยงสัตว์เลี้ยง
SaveX(ctx)
return user, nil
}
ในตัวอย่างนี้เราก่อนที่จะสร้างตัวอย่างของสัตว์เลี้ยงที่ชื่อ Fido จากนั้นสร้างผู้ใช้ที่ชื่อ Alice และเชื่อมโยงตัวอย่างของสัตว์เลี้ยงกับผู้ใช้ โดยใช้วิธี AddPets
3.2 การคิวรี่ Associated Entities
การคิวรี่ associated entities เป็นการดำเนินการที่ธรรมดาใน ent
เช่นเดียวกัน ตัวอย่างเช่น คุณสามารถใช้วิธี Query{Edge}
เพื่อเรียกดู entities ที่เกี่ยวข้องกับ entity ที่กำหนด
ต่อจากตัวอย่างของผู้ใช้และสัตว์เลี้ยงของเรา นี่คือวิธีการคิวรี่สัตว์เลี้ยงทั้งหมดที่เป็นเจ้าของโดยผู้ใช้:
// คิวรี่สัตว์เลี้ยงทั้งหมดของผู้ใช้
func QueryUserPets(ctx context.Context, client *ent.Client, userID int) ([]*ent.Pet, error) {
pets, err := client.User.
Get(ctx, userID). // รับ instance ของผู้ใช้ตาม user ID
QueryPets(). // คิวรี่ entities ของสัตว์เลี้ยงที่เกี่ยวข้องกับผู้ใช้
All(ctx) // ส่งคืน entities ทั้งหมดที่ถูกคิวรี่
if err != nil {
return nil, err
}
return pets, nil
}
ในโค้ดด้านบน เราจะรับ instance ของผู้ใช้ตาม user ID จากนั้นเรียกใช้วิธี QueryPets
เพื่อดึงข้อมูล entities ของสัตว์เลี้ยงที่เกี่ยวข้องกับผู้ใช้
หมายเหตุ: เครื่องมือสร้างโค้ดของ
ent
สร้าง API โดยอัตโนมัติสำหรับการคิวรี่ความสัมพันธ์จาก entities ที่กำหนดไว้ แนะนำให้ตรวจสอบโค้ดที่สร้างขึ้นมาด้วย
โหลดข้อมูลสัมพันธ์ของมิตร
ถ้าเราต้องการดึงข้อมูลของผู้ใช้ทั้งหมดจากฐานข้อมูลและโหลดข้อมูลสัมพันธ์ของสัตว์เลี้ยง เราสามารถทำได้โดยเขียนโค้ดต่อไปนี้:
users, err := client.User.
Query().
WithPets().
All(ctx)
if err != nil {
// จัดการข้อผิดพลาด
return err
}
for _, u := range users {
for _, p := range u.Edges.Pets {
fmt.Printf("ผู้ใช้ (%v) เป็นเจ้าของสัตว์เลี้ยง (%v)\n", u.ID, p.ID)
}
}
ในตัวอย่างนี้ เราใช้ WithPets
method เพื่อขอ ent โหลดข้อมูลของสัตว์เลี้ยงที่เชื่อมโยงกับผู้ใช้ไป เราสามารถเข้าถึงข้อมูลสัมพันธ์นี้ผ่านฟิลด์ Edges.Pets
ที่ถูกโหลดไว้
โหลดข้อมูลสัมพันธ์หลายอย่างพร้อมกัน
ent ช่วยให้เราโหลดข้อมูลสัมพันธ์หลายอย่างพร้อมกัน และยังระบุการโหลดข้อมูลสัมพันธ์ที่ซ้อนอยู่ด้วย สามารถกรอง จัดเรียง หรือ จำกัดจำนวนของผลลัพธ์ที่โหลดได้ด้วย ตัวอย่างด้านล่างเป็นการโหลดข้อมูลของสัตว์เลี้ยงของผู้ดูแลระบบ และทีมที่พวกเขาเป็นส่วนหนึ่ง พร้อมกับโหลดข้อมูลของผู้ใช้ที่เกี่ยวข้องกับทีมด้วย:
admins, err := client.User.
Query().
Where(user.Admin(true)).
WithPets().
WithGroups(func(q *ent.GroupQuery) {
q.Limit(5) // จำกัดไว้ที่ 5 ทีมแรก
q.Order(ent.Asc(group.FieldName)) // เรียงลำดับตามชื่อทีมจากน้อยไปมาก
q.WithUsers() // โหลดข้อมูลของผู้ใช้ในทีมด้วย
}).
All(ctx)
if err != nil {
// จัดการข้อผิดพลาด
return err
}
for _, admin := range admins {
for _, p := range admin.Edges.Pets {
fmt.Printf("ผู้ดูแลระบบ (%v) เป็นเจ้าของสัตว์เลี้ยง (%v)\n", admin.ID, p.ID)
}
for _, g := range admin.Edges.Groups {
fmt.Printf("ผู้ดูแลระบบ (%v) เป็นส่วนหนึ่งของทีม (%v)\n", admin.ID, g.ID)
for _, u := range g.Edges.Users {
fmt.Printf("ทีม (%v) มีสมาชิก (%v)\n", g.ID, u.ID)
}
}
}
ผ่านตัวอย่างนี้ คุณจะเห็นว่า ent เป็นเครื่องมือที่มีพลังและยืดหยุ่นมาก ด้วยเพียงไม่กี่บรรทัดโค้ดเราสามารถโหลดข้อมูลที่เกี่ยวข้องมาอย่างมีประสิทธิภาพอย่างมาก และจัดเรียงข้อมูลเหล่านั้นให้อยู่ในรูปแบบที่ชัดเจน ทำให้สะดวกสบายในการพัฒนาแอปพลิเคชันที่ใช้ข้อมูลอย่างมาก