1. พื้นฐานของโมเดลและฟิลด์
1.1. การแนะนำถึงการนิยามโมเดล
ในกรอบ ORM โมเดลถูกใช้เพื่ออธิบายความสัมพันธ์ของประเภทของตัวบ่งชี้ในแอปพลิเคชันและตารางฐานข้อมูล โมเดลนิยายคุณสมบัติและความสัมพันธ์ของตัวบ่งชี้ รวมทั้งการกำหนดค่าที่เฉพาะของฐานข้อมูลที่เกี่ยวข้องกับพวกเขา ในเกราะ ent โมเดลทั่งหมดจะถูกใช้เพื่ออธิบายประเภทตัวบ่งชี้ในกราฟ เช่น User
หรือ Group
นิยายโมเดลภายในปกครองรวมถึงคำอธิบายของฟิลด์ของตัวบ่งชี้ (หรือคุณสมบัติ) และเส้น (หรือความสัมพันธ์) รวมทั้งตัวเลือกรองฐานข้อมูลที่เฉพาะของพวกเขา คำอธิบายเหล่านี้สามารถช่วยให้เรากำหนดโครงสร้างทุน หลักทรัพย์ และความสัมพันธ์ของสิ่งที่ใช้สร้างโครงสร้างตารางฐานข้อมูลที่สอดคล้องกันตามโมเดล
1.2. ภาพรวมของฟิลด์
ฟิลด์คือส่วนของโมเดลที่แทนคุณสมบัติของตัวบ่งชี้ พวกเขากำหนดคุณสมบัติของตัวบ่งชี้ เช่นชื่อ อายุ วันที่ เป็นต้น ในเกราะ ent ประเภทของฟิลด์รวมถึงชนิดข้อมูลพื้นฐานต่างๆ เช่น integer, string, boolean, time เป็นต้น รวมทั้งหนึ่งตัวเลือกรองฐานข้อมูลที่เฉพาะของ SQL เช่น UUID, []byte, JSON เป็นต้น
ตารางด้านล่างนี้แสดงประเภทของฟิลด์ที่รองรับโดยกรอก ent
ประเภท | คำอธิบาย |
---|---|
int | ชนิดจำนวนเต็ม |
uint8 | ชนิดเต็มบิตรบวนตัวที่ไม่มีเครียว |
float64 | ชนิดจุดลอย |
bool | ชนิดตรรกะ |
string | ชนิดสตริง |
time.Time | ชนิดเวลา |
UUID | ชนิด UUID |
[]byte | ชนิดอาร์เรย์ของไบต์ (เฉพาะ SQL) |
JSON | ชนิด JSON (เฉพาะ SQL) |
Enum | ชนิด Enum (เฉพาะ SQL) |
อื่นๆ | ชนิดอื่นๆ (เช่น, ช่วง Postgres) |
2. รายละเอียดฟิลด์ของคุณสมบัติ
2.1. ประเภทข้อมูล
ประเภทข้อมูลของคุณสมบัติหรือฟิลด์ในโมเดลตัวบ่งชี้กำหนดรูปแบบของข้อมูลที่สามารถจัดเก็บได้ นี่เป็นส่วนสำคัญของการกำหนดโมเดลในกรอบ ent ด้านล่างคือบางประเภทข้อมูลที่ใช้มากในกรอบ ent
import (
"time"
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// โครงการผู้ใช้.
type User struct {
ent.Schema
}
// ฟิลด์ของผู้ใช้.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age"), // ชนิดจำนวนเต็ม
field.String("name"), // ชนิดสตริง
field.Bool("active"), // ชนิดตรรกะ
field.Float("score"), // ชนิดจุดลอย
field.Time("created_at"), // ชนิดเวลา
}
}
-
int
: แทนค่าจำนวนเต็ม ที่สามารถเป็นได้เป็นint8
,int16
,int32
,int64
, เป็นต้น -
string
: แทนข้อมูลสตริง -
bool
: แทนค่าตรรกะที่ใช้เป็นธง -
float64
: แทนตัวเลขทศนิยม ยังสามารถใช้float32
ได้อีก -
time.Time
: แทนเวลา ที่ใช้เป็นปัจจุบันหรือข้อมูลวันที่ที่กำหนดไว้
พวกเขาจะถูกแมปไปยังประเภทที่สนับสนุนโดยฐานข้อมูลต้นส่วนบน นอกจากนี้ ent
ยังสนับสนุนประเภทที่ซับซ้อนมากขึ้น เช่น UUID
, JSON
, สมการ (Enum
), และสนับสนุนประเภทฐานข้อมูลพิเศษเช่น []byte
(เฉพาะ SQL) และ Other
(เฉพาะ SQL)
2.2. ค่าเริ่มต้น
ฟิลด์สามารถกำหนดค่าเริ่มต้นได้ หากค่าที่เกี่ยวข้องยังไม่ได้ระบุเมื่อสร้างตัวบ่งชี้ ค่าเริ่มต้นจะถูกใช้ ค่าเริ่มต้นสามารถเป็นค่าคงที่หรือค่าที่สร้างขึ้นได้จากฟังก์ชัน ใช้ .Default
เมธอดเพื่อกำหนดค่าเริ่มต้นแบบคงที่ หรือใช้ .DefaultFunc
เพื่อกำหนดค่าเริ่มต้นที่สร้างขึ้นได้จากฟังก์ชัน
// โครงการผู้ใช้.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Time("created_at").
Default(time.Now), // ค่าเริ่มต้นแบบคงที่ของ time.Now
field.String("role").
Default("user"), // ค่าสตริงคงที่
field.Float("score").
DefaultFunc(func() float64 {
return 10.0 // ค่าเริ่มต้นที่สร้างขึ้นจากฟังก์ชัน
}),
}
}
2.3. ความสามารถในการเลือกใช้และค่าศูนย์
ตามค่าเริ่มต้น ฟิลด์จำเป็นต้องกรอกข้อมูลเสมอ เพื่อกำหนดฟิลด์ที่เป็นตัวเลือก ให้ใช้เมธอด .Optional()
ได้ เมธอดที่เลือกได้จะถูกกำหนดเป็นฟิลด์ที่สามารถเป็นค่าว่างในฐานข้อมูล ตัวเลือก Nillable
อนุญาตให้ฟิลด์ถูกกำหนดโดยชัดเจนเป็น nil
เพื่อแยกแยะระหว่างค่าศูนย์ของฟิลด์และสถานะที่ไม่ได้ตั้งค่า.
// โครงสร้างของผู้ใช้
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("nickname").Optional(), // ฟิลด์ที่เป็นตัวเลือกไม่จำเป็นต้องกรอก
field.Int("age").Optional().Nillable(), // ฟิลด์ที่เป็น Nillable สามารถถูกกำหนดเป็น nil
}
}
เมื่อใช้โมเดลที่กำหนดไว้ด้านบน ฟิลด์ age
สามารถยอมรับทั้งค่า nil
เพื่อแสดงว่าไม่ได้ตั้งค่า และค่าศูนย์ที่ไม่เป็น nil
ได้เช่นกัน.
2.4. ความเป็นเอกลักษณ์ของฟิลด์
ฟิลด์ที่เป็นเอกลักษณ์จะตรวจสอบให้แน่ใจว่าไม่มีค่าที่ซ้ำกันในตารางฐานข้อมูล ใช้เมธอด Unique()
เพื่อกำหนดฟิลด์ที่เป็นเอกลักษณ์ ขณะกำหนดความสำคัญในด้านความสมบูรณ์ข้อมูล อย่างเช่น อีเมลผู้ใช้หรือชื่อผู้ใช้งาน ควรใช้ฟิลด์ที่เป็นเอกลักษณ์.
// โครงสร้างของผู้ใช้
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("email").Unique(), // ฟิลด์ที่เป็นเอกลักษณ์เพื่อหลีกเลี่ยงที่อยู่อีเมลที่ซ้ำกัน
}
}
นี้จะสร้างข้อจำกัดที่เป็นเอกลักษณ์ในฐานข้อมูลข้องอุปกรณ์เพื่อป้องกันการเพิ่มค่าที่ซ้ำกัน.
2.5. การสร้างดัชนีของฟิลด์
การสร้างดัชนีของฟิลด์ใช้เพื่อปรับปรุงประสิทธิภาพของคิวรี่ฐานข้อมูล โดยเฉพาะในฐานข้อมูลที่ใหญ่ ในโครงสร้าง ent
สามารถใช้เมธอด .Indexes()
เพื่อสร้างดัชนี.
import "entgo.io/ent/schema/index"
// โครงสร้างของผู้ใช้
func (User) Indexes() []ent.Index {
return []ent.Index{
index.Fields("email"), // สร้างดัชนีบนฟิลด์ 'email'
index.Fields("name", "age").Unique(), // สร้างดัชนีผสมที่เป็นเอกลักษณ์
}
}
การใช้ดัชนีสามารถใช้เมืองฟิลด์ที่ถูกคิวรี่บ่อย แต่สิ่งสำคัญที่สุดคือมีการใช้ดัชนีมากเกินไปอาจทำให้ประสิทธิภาพของการเขียนลดลง เพราะสถานการณ์จริงจะต้องมีการสมดุลในการตัดสินใจสร้างดัชนี.
2.6. แท็กที่กำหนดเอง
ในโครงสร้าง ent
คุณสามารถใช้เมธอด StructTag
เพื่อเพิ่มแท็กที่กำหนดเองในฟิลด์ของตัวเองที่ถูกสร้างขึ้น แท็กเหล่านี้เป็นประโยชน์อย่างมากสำหรับการนำไปใช้ในการเข้ารหัสแบบ JSON และ XML ในตัวอย่างด้านล่างนี้ เราจะเพิ่มแท็กแบบ JSON และ XML สำหรับฟิลด์ name
.
// ฟิลด์ของผู้ใช้
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").
// เพิ่มแท็กที่กำหนดเองโดยใช้เมธอด StructTag
// ที่นี่ กำหนดแท็ก JSON สำหรับฟิลด์ชื่อเป็น 'username' และละทิ้งจากการเขียนเมื่อฟิลด์ว่าง (omitempty)
// นอกจากนั้น กำหนดแท็ก XML สำหรับเข้ารหัสเป็น 'name'
StructTag(`json:"username,omitempty" xml:"name"`),
}
}
ขณะที่เข้ารหัสด้วย JSON หรือ XML ตัวเลือก omitempty
บ่งบอกว่าหากฟิลด์ name
ห่างเปล่า แล้วฟิลด์นี้จะถูกละทิ้งจากผลลัพธ์การเข้ารหัส สิ่งนี้เป็นประโยชน์อย่างมากในการลดขนาดของตัวรายการตอบกลับเมื่อเขียน API.
นี่ยังแสดงถึงว่าจะกำหนดแท็กหลายรายการสำหรับฟิลด์เดียวกันพร้อมกัน JSON ใช้แท็ก json
XML ใช้แท็ก xml
และพวกเขาถูกคั่นด้วยช่องว่าง แท็กเหล่านี้จะถูกใช้โดยฟังก์ชันไลบรารี่ เช่น encoding/json
และ encoding/xml
เมื่อทำการวิเคราะห์ข้อมูลไปใช้ในการเข้ารหัสหรือถอดรหัส.
3.1. ตัวตรวจสอบที่ซ่อนอยู่
Framework มีตัวตรวจสอบที่ซ่อนอยู่สำหรับการตรวจสอบความถูกต้องของข้อมูลที่พบบ่อยบนชนิดของฟิลด์ต่าง ๆ การใช้ตัวตรวจสอบที่ซ่อนอยู่นี้สามารถทำให้กระบวนการการพัฒนาง่ายขึ้นและกำหนดขอบเขตข้อมูลที่ถูกต้องหรือรูปแบบสำหรับฟิลด์ได้อย่างรวดเร็ว
ต่อไปนี้คือตัวอย่างของตัวตรวจสอบฟิลด์ที่ซ่อนอยู่:
- ตัวตรวจสอบสำหรับชนิดตัวเลข:
-
Positive()
: ตรวจสอบว่าค่าของฟิลด์เป็นจำนวนเต็มบวกหรือไม่ -
Negative()
: ตรวจสอบว่าค่าของฟิลด์เป็นจำนวนเต็มลบหรือไม่ -
NonNegative()
: ตรวจสอบว่าค่าของฟิลด์เป็นจำนวนเต็มบวกหรือศูนย์หรือไม่ -
Min(i)
: ตรวจสอบว่าค่าของฟิลด์มีค่ามากกว่าค่าขั้นต่ำที่กำหนดi
-
Max(i)
: ตรวจสอบว่าค่าของฟิลด์มีค่าน้อยกว่าค่าสูงสุดที่กำหนดi
-
- ตัวตรวจสอบสำหรับชนิด
string
:-
MinLen(i)
: ตรวจสอบความยาวขั้นต่ำของสตริง -
MaxLen(i)
: ตรวจสอบความยาวสูงสุดของสตริง -
Match(regexp.Regexp)
: ตรวจสอบว่าสตริงตรงกับ regular expression ที่กำหนด -
NotEmpty
: ตรวจสอบว่าสตริงไม่ว่างเปล่า
-
มาดูตัวอย่างการเขียนโค้ดที่เข้ากันได้กับการใช้งานกันในทางปฏิบัติ ในตัวอย่างนี้มีการสร้างโมเดล User
ซึ่งรวมถึงฟิลด์ชนิดจำนวนเต็มบวก age
และฟิลด์ email
ที่มีรูปแบบคงที่:
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age").
Positive(),
field.String("email").
Match(regexp.MustCompile(`^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$`)),
}
}
3.2. ตัวตรวจสอบที่กำหนดเอง
แม้ว่าตัวตรวจสอบที่ซ่อนอยู่สามารถจัดการกับความต้องการการตรวจสอบที่ซับซ้อนได้มากมาย แต่บางครั้งคุณอาจต้องการตรวจสอบโลจิกที่ซับซ้อนมากขึ้น เช่นเดียวกับนี้ คุณสามารถเขียนตัวตรวจสอบที่กำหนดเองเพื่อตอบสนองกับกฎธุรกิจที่เฉพาะเจาะจงได้
ตัวตรวจสอบที่กำหนดเองคือฟังก์ชันที่รับค่าของฟิลด์และส่งคืน error
ถ้า error
ที่ส่งคืนไม่ว่างเปล่า จะหมายถึงการตวจสอบล้มเหลว รูปแบบทั่วไปของตัวตรวจสอบที่กำหนดเองจะเป็นดังนี้:
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("phone").
Validate(func(s string) error {
// ตรวจสอบว่าเบอร์โทรตรงกับรูปแบบที่คาดหวังหรือไม่
matched, _ := regexp.MatchString(`^\+?[1-9]\d{1,14}$`, s)
if !matched {
return errors.New("รูปแบบเบอร์โทรไม่ถูกต้อง")
}
return nil
}),
}
}
เช่นที่แสดงในตัวอย่างข้างต้น เราได้สร้างตัวตรวจสอบที่กำหนดเองเพื่อตรวจสอบรูปแบบของเบอร์โทร
3.3. ข้อจำกัด
ข้อจำกัดคือกฎที่บังคับกำหนดกฎเฉพาะบนวัตถุในฐานข้อมูล ทำให้เกิดความถูกต้องและสอดคล้องข้อมูล เช่นการป้องกันการป้อนข้อมูลที่ไม่ถูกต้องหรือกำหนดความสัมพันธ์ข้อมูล
ข้อจำกัดที่พบบ่อยในฐานข้อมูลรวมถึง:
- ข้อจำกัด Primary key: ให้แน่ใจว่าแต่ละบันทึกในตารางเป็นค่าที่ไม่ซ้ำกัน
- ข้อจำกัด Unique: ให้แน่ใจว่าค่าของคอลัมน์หรือคอลัมน์ร่วมกันเป็นค่าที่ไม่ซ้ำกันในตาราง
- ข้อจำกัด Foreign key: กำหนดความสัมพันธ์ระหว่างตาราง เพื่อให้มั่นใจถึงความสอดคล้องของการอ้างอิง
- ข้อจำกัด Check: ให้แน่ใจว่าค่าของฟิลด์ตรงตามเงื่อนไขที่กำหนด
ในโมเดลของ entity คุณสามารถกำหนดข้อจำกัดเพื่อรักษาความถูกต้องของข้อมูลตามนี้:
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("username").
Unique(), // ข้อจำกัด Unique เพื่อรักษาให้ชื่อผู้ใช้เป็นค่าที่ไม่ซ้ำกันในตาราง
field.String("email").
Unique(), // ข้อจำกัด Unique เพื่อรักษาให้อีเมลเป็นค่าที่ไม่ซ้ำกันในตาราง
}
}
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("friends", User.Type).
Unique(), // ข้อจำกัด Foreign key, สร้างความสัมพันธ์ด้วยผู้ใช้อื่นๆที่เป็นค่าที่ไม่ซ้ำกัน
}
}
สรุปแล้ว การตรวจสอบฟิลด์และข้อจำกัดเป็นสิ่งสำคัญสำหรับการรักษาคุณภาพของข้อมูลและป้องกันข้อผิดพลาดของข้อมูลที่ไม่คาดคิด การใช้เครื่องมือที่ framework ent
ต้องการสามารถทำให้กระบวนการนี้ง่ายขึ้นและน่าเชื่อถือมากขึ้นได้