1. Dasar Model dan Field
1.1. Pengenalan Definisi Model
Pada kerangka ORM, model digunakan untuk menggambarkan hubungan pemetaan antara jenis entitas dalam aplikasi dan tabel database. Model ini mendefinisikan properti dan hubungan dari entitas, serta konfigurasi khusus database yang terkait dengan mereka. Dalam kerangka ent, model biasanya digunakan untuk menggambarkan jenis entitas dalam graf, seperti Pengguna
atau Grup
.
Definisi model biasanya mencakup deskripsi bidang entitas (atau properti) dan sisi (atau hubungan), serta beberapa opsi khusus database. Deskripsi ini dapat membantu kita mendefinisikan struktur, properti, dan hubungan entitas, dan dapat digunakan untuk menghasilkan struktur tabel database yang sesuai berdasarkan model.
1.2. Tinjauan Field
Field adalah bagian dari model yang mewakili properti entitas. Mereka mendefinisikan properti dari entitas, seperti nama, usia, tanggal, dll. Dalam kerangka ent, tipe field mencakup berbagai tipe data dasar, seperti integer, string, boolean, time, dll, serta beberapa tipe khusus SQL, seperti UUID, []byte, JSON, dll.
Tabel di bawah ini menunjukkan tipe-tipe field yang didukung oleh kerangka ent:
Tipe | Deskripsi |
---|---|
int | Tipe integer |
uint8 | Tipe integer 8-bit tanpa tanda |
float64 | Tipe bilangan desimal |
bool | Tipe boolean |
string | Tipe string |
time.Time | Tipe waktu |
UUID | Tipe UUID |
[]byte | Tipe array byte (hanya SQL) |
JSON | Tipe JSON (hanya SQL) |
Enum | Tipe Enum (hanya SQL) |
Lainnya | Tipe lainnya (mis., Rentang Postgres) |
2. Rincian Properti Field
2.1. Tipe Data
Tipe data dari atribut atau field dalam model entitas menentukan bentuk data yang dapat disimpan. Ini adalah bagian penting dari definisi model dalam kerangka ent. Berikut adalah beberapa tipe data yang umum digunakan dalam kerangka ent
.
import (
"time"
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// Skema Pengguna.
type Pengguna struct {
ent.Schema
}
// Bidang-bidang Pengguna.
func (Pengguna) Fields() []ent.Field {
return []ent.Field{
field.Int("usia"), // Tipe integer
field.String("nama"), // Tipe string
field.Bool("aktif"), // Tipe boolean
field.Float("skor"), // Tipe bilangan desimal
field.Time("dibuat_pada"), // Tipe timestamp
}
}
-
int
: Mewakili nilai integer, yang bisa berupaint8
,int16
,int32
,int64
, dll. -
string
: Mewakili data string. -
bool
: Mewakili nilai boolean, umumnya digunakan sebagai tanda. -
float64
: Mewakili bilangan desimal, juga dapat menggunakanfloat32
. -
time.Time
: Mewakili waktu, umumnya digunakan untuk timestamp atau data tanggal.
Tipe field ini akan dipetakan ke tipe-tipe yang sesuai didukung oleh database yang mendasarinya. Selain itu, ent
mendukung tipe-tipe yang lebih kompleks seperti UUID
, JSON
, enum (Enum
), dan dukungan untuk tipe-tipe database khusus seperti []byte
(hanya SQL) dan Lainnya
(hanya SQL).
2.2. Nilai Default
Field dapat dikonfigurasi dengan nilai default. Jika nilai yang sesuai tidak ditentukan saat membuat entitas, nilai default akan digunakan. Nilai default bisa berupa nilai tetap atau nilai yang dihasilkan secara dinamis dari sebuah fungsi. Gunakan metode .Default
untuk mengatur nilai default statis, atau gunakan .DefaultFunc
untuk mengatur nilai default yang dihasilkan secara dinamis.
// Skema Pengguna.
func (Pengguna) Fields() []ent.Field {
return []ent.Field{
field.Time("dibuat_pada").
Default(time.Now), // Nilai default tetap dari time.Now
field.String("peran").
Default("pengguna"), // Nilai string konstan
field.Float("skor").
DefaultFunc(func() float64 {
return 10.0 // Nilai default yang dihasilkan oleh sebuah fungsi
}),
}
}
2.3. Opsi Keterwajiban dan Nilai Nol
Secara default, bidang-bidang diwajibkan. Untuk mendeklarasikan suatu bidang opsional, gunakan metode .Optional()
. Bidang opsional akan dinyatakan sebagai bidang-bidang yang dapat bernilai null di dalam basis data. Opsional Nillable
memungkinkan bidang-bidang untuk secara eksplisit diatur sebagai nil
, membedakan antara nilai nol dari suatu bidang dan suatu keadaan yang belum diatur.
// Skema pengguna.
func (Pengguna) Fields() []ent.Field {
return []ent.Field{
field.String("namaPanggilan").Optional(), // Bidang opsional tidak diwajibkan
field.Int("umur").Optional().Nillable(), // Bidang yang dapat diatur sebagai nil
}
}
Dengan menggunakan model yang telah didefinisikan di atas, bidang umur
dapat menerima baik nilai nil
untuk menunjukkan belum diatur, maupun nilai nol non-nil
.
2.4. Unik Bidang
Bidang unik memastikan bahwa tidak ada nilai duplikat di dalam tabel basis data. Gunakan metode Unique()
untuk mendefinisikan suatu bidang unik. Ketika menjaga integritas data sebagai suatu persyaratan yang kritis, seperti untuk alamat email atau nama pengguna pengguna, bidang unik harus digunakan.
// Skema pengguna.
func (Pengguna) Fields() []ent.Field {
return []ent.Field{
field.String("email").Unique(), // Bidang unik untuk menghindari alamat email ganda
}
}
Ini akan membuat suatu kendala unik di dalam basis data yang mendasarinya untuk mencegah penyisipan nilai-nilai duplikat.
2.5. Pemasangan Indeks Bidang
Pemasangan indeks bidang digunakan untuk meningkatkan kinerja kueri basis data, terutama dalam basis data yang besar. Di dalam kerangka kerja ent
, metode .Indexes()
dapat digunakan untuk membuat indeks.
import "entgo.io/ent/schema/index"
// Skema pengguna.
func (Pengguna) Indexes() []ent.Index {
return []ent.Index{
index.Fields("email"), // Buat indeks pada bidang 'email'
index.Fields("nama", "umur").Unique(), // Buat indeks komposit unik
}
}
Indeks dapat dimanfaatkan untuk bidang-bidang yang sering ditanya, namun penting untuk dicatat bahwa terlalu banyak indeks dapat mengakibatkan penurunan kinerja operasi tulis. Oleh karena itu, keputusan untuk membuat indeks harus seimbang berdasarkan keadaan yang sebenarnya.
2.6. Tag Kustom
Di dalam kerangka kerja ent
, Anda dapat menggunakan metode StructTag
untuk menambahkan tag-tag kustom ke bidang-bidang struktur entitas yang dihasilkan. Tag-tag ini sangat berguna untuk menerapkan operasi seperti penyandian JSON dan penyandian XML. Pada contoh di bawah, kita akan menambahkan tag-tag JSON dan XML kustom untuk bidang nama
.
// Bidang-bidang Pengguna.
func (Pengguna) Fields() []ent.Field {
return []ent.Field{
field.String("nama").
// Tambahkan tag-tag kustom menggunakan metode StructTag
// Di sini, aturlah tag JSON untuk bidang nama menjadi 'username' dan abaikan jika bidang tersebut kosong (omitempty)
// Juga, aturlah tag XML untuk penyandian menjadi 'nama'
StructTag(`json:"username,omitempty" xml:"name"`),
}
}
Saat menyandikan dengan JSON atau XML, opsi omitempty
menunjukkan bahwa jika bidang nama
kosong, maka bidang ini akan dihilangkan dari hasil penyandian. Ini sangat berguna untuk mengurangi ukuran tubuh respons saat menulis API.
Ini juga menunjukkan bagaimana mengatur tag-tag ganda untuk bidang yang sama secara bersamaan. Tag-tag JSON menggunakan kunci json
, tag-tag XML menggunakan kunci xml
, dan mereka dipisahkan oleh spasi. Tag-tag ini akan digunakan oleh fungsi-fungsi perpustakaan seperti encoding/json
dan encoding/xml
saat menguraikan struktur untuk penyandian atau penguraian.
3. Validasi Bidang dan Kendala
Validasi bidang adalah aspek penting dari desain basis data untuk memastikan konsistensi dan validitas data. Di bagian ini, kita akan membahas penggunaan validator bawaan, validator kustom, dan berbagai kendala untuk meningkatkan integritas dan kualitas data dalam model entitas.
3.1. Validator Bawaan
Framework menyediakan serangkaian validator bawaan untuk melakukan pemeriksaan validitas data umum pada berbagai jenis bidang. Dengan menggunakan validator bawaan ini, proses pengembangan dapat disederhanakan dan rentang data yang valid atau format bidang dapat dengan cepat ditentukan.
Berikut beberapa contoh validator bawaan bidang:
- Validator untuk tipe numerik:
-
Positive()
: Memvalidasi apakah nilai bidang merupakan angka positif. -
Negative()
: Memvalidasi apakah nilai bidang merupakan angka negatif. -
NonNegative()
: Memvalidasi apakah nilai bidang merupakan angka non-negatif. -
Min(i)
: Memvalidasi apakah nilai bidang lebih besar dari nilai minimumi
yang diberikan. -
Max(i)
: Memvalidasi apakah nilai bidang lebih kecil dari nilai maksimumi
yang diberikan.
-
- Validator untuk tipe
string
:-
MinLen(i)
: Memvalidasi panjang minimum dari sebuah string. -
MaxLen(i)
: Memvalidasi panjang maksimum dari sebuah string. -
Match(regexp.Regexp)
: Memvalidasi apakah string cocok dengan ekspresi reguler yang diberikan. -
NotEmpty
: Memvalidasi apakah string tidak kosong.
-
Mari kita lihat contoh kode praktis. Pada contoh ini, dibuat model User
, yang mencakup bidang bertipe bilangan bulat non-negatif age
dan bidang email
dengan format tetap:
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. Validator Kustom
Meskipun validator bawaan dapat menangani banyak kebutuhan validasi umum, terkadang Anda mungkin memerlukan logika validasi yang lebih kompleks. Dalam kasus seperti itu, Anda dapat menulis validator kustom untuk memenuhi aturan bisnis tertentu.
Validator kustom merupakan fungsi yang menerima nilai bidang dan mengembalikan error
. Jika error
yang dikembalikan tidak kosong, itu menunjukkan kegagalan validasi. Format umum dari validator kustom adalah sebagai berikut:
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("phone").
Validate(func(s string) error {
// Verifikasi apakah nomor telepon memenuhi format yang diharapkan
cocok, _ := regexp.MatchString(`^\+?[1-9]\d{1,14}$`, s)
if !cocok {
return errors.New("Format nomor telepon tidak benar")
}
return nil
}),
}
}
Seperti yang ditunjukkan di atas, kita telah membuat validator kustom untuk memvalidasi format nomor telepon.
3.3. Kendala
Kendala adalah aturan yang menegakkan aturan tertentu pada objek basis data. Mereka dapat digunakan untuk menjamin kebenaran dan konsistensi data, seperti mencegah input data yang tidak valid atau menentukan hubungan data.
Kendala basis data umum meliputi:
- Kendala kunci primer: Memastikan bahwa setiap catatan dalam tabel bersifat unik.
- Kendala unik: Memastikan bahwa nilai kolom atau kombinasi kolom bersifat unik di tabel.
- Kendala kunci asing: Mendefinisikan hubungan antara tabel, memastikan integritas referensial.
- Kendala periksa: Memastikan bahwa nilai bidang memenuhi kondisi spesifik.
Dalam model entitas, Anda dapat mendefinisikan kendala untuk menjaga integritas data sebagai berikut:
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("username").
Unique(), // Kendala unik untuk memastikan username unik dalam tabel.
field.String("email").
Unique(), // Kendala unik untuk memastikan email unik dalam tabel.
}
}
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("friends", User.Type).
Unique(), // Kendala kunci asing, menciptakan hubungan tepi unik dengan pengguna lain.
}
}
Secara keseluruhan, validasi bidang dan kendala sangat penting untuk memastikan kualitas data yang baik dan menghindari kesalahan data yang tidak terduga. Memanfaatkan alat yang disediakan oleh kerangka kerja ent
dapat membuat proses ini lebih sederhana dan dapat diandalkan.