1. Model ve Field Temelleri
1.1. Model Tanımına Giriş
Bir ORM çerçevesinde, bir model uygulama içindeki varlık türleri ile veritabanı tabloları arasındaki eşleşme ilişkisini açıklamak için kullanılır. Model, varlığın özelliklerini ve ilişkilerini, bunlarla ilişkili veritabanı özgü yapılandırmaları tanımlar. Ent çerçevesinde, modeller genellikle Kullanıcı
veya Grup
gibi grafikte varlık türlerini tanımlamak için kullanılır.
Model tanımları genellikle varlığın alanlarının (veya özelliklerinin) ve kenarlarının (veya ilişkilerinin) yanı sıra bunlarla ilişkili veritabanı özgü seçeneklerin açıklamalarını içerir. Bu açıklamalar, bize varlığın yapısını, özelliklerini ve ilişkilerini tanımlamamıza yardımcı olur ve modele dayalı olarak karşılık gelen veritabanı tablo yapısını oluşturmak için kullanılabilir.
1.2. Alan Genel Bakışı
Alanlar, varlık özelliklerini temsil eden modelin bir parçasıdır. Varlığın özelliklerini (örneğin: isim, yaş, tarih vb.) tanımlar. Ent çerçevesinde, alan tipleri, tamsayı, dize, mantıksal, zaman vb. gibi çeşitli temel veri tiplerini içerir; ayrıca UUID, []byte, JSON gibi bazı SQL özel tiplerini de içerir.
Aşağıdaki tablo, ent çerçevesi tarafından desteklenen alan tiplerini göstermektedir:
Tip | Açıklama |
---|---|
int | Tamsayı tipi |
uint8 | 8-bit işaretsiz tamsayı tipi |
float64 | Ondalık sayı tipi |
bool | Mantıksal tip |
string | Dize tipi |
time.Time | Zaman tipi |
UUID | UUID tipi |
[]byte | Bayt dizisi tipi (Sadece SQL) |
JSON | JSON tipi (Sadece SQL) |
Enum | Enum tipi (Sadece SQL) |
Diğer | Diğer tipler (ör. PostgreSQL Aralığı) |
2. Alan Özelliği Detayları
2.1. Veri Tipleri
Bir varlık modelindeki özniteliğin veya alanın veri tipi depolanabilecek veri biçimini belirler. Bu, ent çerçevesinde model tanımının kritik bir parçasıdır. Aşağıda, ent
çerçevesinde sıkça kullanılan bazı veri tipleri bulunmaktadır.
import (
"time"
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// Kullanıcı şeması.
type User struct {
ent.Schema
}
// Kullanıcının alanları.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age"), // Tamsayı tipi
field.String("name"), // Dize tipi
field.Bool("active"), // Mantıksal tip
field.Float("score"), // Ondalık sayı tipi
field.Time("created_at"), // Zaman damgası tipi
}
}
-
int
: Tamsayı değerleri temsil eder,int8
,int16
,int32
,int64
vb. olabilir. -
string
: Dize verisini temsil eder. -
bool
: Mantıksal değerleri temsil eder, genellikle bayrak olarak kullanılır. -
float64
: Ondalık sayıları temsil eder, aynı zamandafloat32
kullanılabilir. -
time.Time
: Zamanı temsil eder, genellikle zaman damgaları veya tarih verileri için kullanılır.
Bu alan tipleri, altta yatan veritabanı tarafından desteklenen karşılık gelen tiplere eşlenecektir. Ek olarak, ent
, UUID
, JSON
, enum'lar (Enum
) gibi daha karmaşık tipleri ve []byte
(Sadece SQL) gibi özel veritabanı tiplerini ve Diğer
(Sadece SQL) desteğini destekler.
2.2. Varsayılan Değerler
Alanlar, varsayılan değerlerle yapılandırılabilir. Bir varlık oluşturulurken karşılık gelen değer belirtilmezse, varsayılan değer kullanılacaktır. Varsayılan değer, sabit bir değer veya bir işlevden dinamik olarak oluşturulan bir değer olabilir. Statik bir varsayılan değer belirlemek için .Default
yöntemini kullanın veya dinamik olarak oluşturulan bir varsayılan değer belirlemek için .DefaultFunc
'ı kullanın.
// Kullanıcı şeması.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Time("created_at").
Default(time.Now), // time.Now'un sabit varsayılan değeri
field.String("role").
Default("user"), // Sabit bir dize değeri
field.Float("score").
DefaultFunc(func() float64 {
return 10.0 // Bir işlev tarafından oluşturulan varsayılan değer
}),
}
}
2.3. Alan Opsiyonellik ve Sıfır Değerler
Varsayılan olarak, alanlar zorunludur. Bir isteğe bağlı alanı tanımlamak için .Optional()
yöntemini kullanın. İsteğe bağlı alanlar veritabanında null olarak bildirilecektir. Nillable
seçeneği, alanların açıkça nil
olarak ayarlanmasına izin verir, bir alanın sıfır değeri ve ayarlanmamış bir durum arasındaki farkı belirtir.
// Kullanıcı şeması.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("takmaAd").Optional(), // Opsiyonel alan gerekli değil
field.Int("yaş").Optional().Nillable(), // Null olabilen alan `nil` olarak ayarlanabilir
}
}
Yukarıdaki modeli kullanırken, yaş
alanı hem ayarlanmamış durumu gösteren nil
değerlerini kabul edebilir hem de non-nil
sıfır değerlerini kabul edebilir.
2.4. Alanın Benzersizliği
Benzersiz alanlar, veritabanı tablosunda yinelenen değerler olmamasını sağlar. Bir benzersiz alanı tanımlamak için Unique()
yöntemini kullanın. Özellikle kullanıcı e-postaları veya kullanıcı adları gibi veri bütünlüğünü sağlamak için kritik bir gereksinim olduğunda benzersiz alanlar kullanılmalıdır.
// Kullanıcı şeması.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("email").Unique(), // Tekrarlanan e-posta adreslerini önlemek için benzersiz alan
}
}
Bu, altta yatan veritabanında yinelenen değerlerin eklenmesini engellemek için benzersiz bir kısıtlama oluşturacaktır.
2.5. Alan Endeksleme
Alan endeksleme, özellikle büyük veritabanlarında veritabanı sorgularının performansını artırmak için kullanılır. ent
çerçevesinde, .Indexes()
yöntemi endeks oluşturmak için kullanılabilir.
import "entgo.io/ent/schema/index"
// Kullanıcı şeması.
func (User) Indexes() []ent.Index {
return []ent.Index{
index.Fields("email"), // 'email' alanı üzerinde bir endeks oluştur
index.Fields("ad", "yaş").Unique(), // Benzersiz bileşik bir endeks oluştur
}
}
Endeksler sıkça sorgulanan alanlar için kullanılabilir, ancak çok fazla endeks yazma işlemi performansını azaltabilir. Bu nedenle, endeks oluşturma kararı gerçek durumlara göre dengelenmelidir.
2.6. Özel Etiketler
ent
çerçevesinde, oluşturulan varlık yapısı alanlarına özel etiketler eklemek için StructTag
yöntemini kullanabilirsiniz. Bu etiketler, JSON kodlaması ve XML kodlaması gibi işlemleri gerçekleştirmek için çok kullanışlıdır. Aşağıdaki örnekte, ad
alanı için özel JSON ve XML etiketleri ekleyeceğiz.
// Kullanıcı alanları.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("ad").
// `StructTag` yöntemini kullanarak özel etiketler ekleyin
// Burada, ad alanı için JSON etiketini 'kullanıcıadı' olarak ayarlayın ve alan boşken (omitempty) görmezden gelin
// Ayrıca kodlamada 'ad' için XML etiketini ayarlayın
StructTag(`json:"kullanıcıadı,omitempty" xml:"ad"`),
}
}
JSON veya XML ile kodlarken, omitempty
seçeneği, ad
alanı boşsa, bu alanın kodlama sonucundan çıkarılacağını belirtir. Bu, API'ler yazarken yanıt gövdesinin boyutunu azaltmak için çok kullanışlıdır.
Bu ayrıca aynı alana birden fazla etiket eklemeyi aynı anda nasıl ayarlayacağımızı göstermektedir. JSON etiketleri json
anahtarını kullanır, XML etiketleri ise xml
anahtarını kullanır ve boşluklarla ayrılır. Bu etiketler, encoding/json
ve encoding/xml
gibi kütüphane işlevleri tarafından, yapıyı kodlamak veya kodlamak için kullanılırken kullanılacaktır.
3. Alan Doğrulama ve Kısıtları
Alan doğrulama, varlık modelindeki veri tutarlılığını ve geçerliliğini sağlamak için önemli bir yönüdür. Bu bölümde, yerleşik doğrulayıcıları, özel doğrulayıcıları ve çeşitli kısıtları kullanarak veri bütünlüğünü ve kalitesini artırmak için inceleyeceğiz.
3.1. Yerleşik Doğrulayıcılar
Çerçeve, farklı türlerdeki alanlarda yaygın veri geçerlilik kontrollerini gerçekleştirmek için bir dizi yerleşik doğrulayıcı sağlar. Bu yerleşik doğrulayıcıların kullanılması geliştirme sürecini basitleştirebilir ve alanlar için geçerli veri aralıklarını veya formatlarını hızlı bir şekilde tanımlamanıza yardımcı olabilir.
İşte bazı yerleşik alan doğrulayıcılarının örnekleri:
- Sayısal türler için doğrulayıcılar:
-
Positive()
: Alanın değerinin pozitif bir sayı olup olmadığını doğrular. -
Negative()
: Alanın değerinin negatif bir sayı olup olmadığını doğrular. -
NonNegative()
: Alanın değerinin non-negatif bir sayı olup olmadığını doğrular. -
Min(i)
: Alanın değerinin verilen minimum değeri
'den büyük olup olmadığını doğrular. -
Max(i)
: Alanın değerinin verilen maksimum değeri
'den küçük olup olmadığını doğrular.
-
-
string
türü için doğrulayıcılar:-
MinLen(i)
: Bir dizenin minimum uzunluğunu doğrular. -
MaxLen(i)
: Bir dizenin maksimum uzunluğunu doğrular. -
Match(regexp.Regexp)
: Dizenin belirtilen düzenli ifadeyle eşleşip eşleşmediğini doğrular. -
NotEmpty
: Dizenin boş olup olmadığını doğrular.
-
Pratik bir kod örneği için aşağıdaki örneğe göz atalım. Bu örnekte, bir User
modeli oluşturulur; bu modelde non-negatif bir tamsayı türünde age
alanı ve belirli bir formata sahip email
alanı bulunmaktadır:
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. Özel Doğrulayıcılar
Yerleşik doğrulayıcılar çoğu yaygın doğrulama gereksinimini karşılayabilirken, bazen daha karmaşık doğrulama mantığına ihtiyaç duyabilirsiniz. Bu tür durumlarda, belirli iş kurallarını karşılamak için özel doğrulayıcılar yazabilirsiniz.
Bir özel doğrulayıcı, bir alan değeri alır ve bir error
döndürür. Döndürülen error
boş değilse, doğrulama hatasını gösterir. Bir özel doğrulayıcının genel formatı aşağıdaki gibidir:
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("phone").
Validate(func(s string) error {
// Telefon numarasının beklenen formata uygun olup olmadığını doğrulayın
eşleşmiş, _ := regexp.MatchString(`^\+?[1-9]\d{1,14}$`, s)
if !eşleşmiş {
return errors.New("Telefon numarası formatı yanlış")
}
return nil
}),
}
}
Yukarıdaki gibi, bir telefon numarasının formatını doğrulamak için özel bir doğrulayıcı oluşturduk.
3.3. Kısıtlamalar
Kısıtlamalar, belirli kuralları bir veritabanı nesnesine zorlayan kurallardır. Bunlar, geçersiz veri girişini önlemek veya verilerin ilişkilerini tanımlamak gibi verilerin doğruluğunu ve tutarlılığını sağlamak için kullanılabilir.
Yaygın veritabanı kısıtlamaları şunları içerir:
- Birincil anahtar kısıtlaması: Tablodaki her kaydın benzersiz olmasını sağlar.
- Benzersiz kısıtlama: Bir sütunun veya sütun kombinasyonunun tabloda benzersiz olmasını sağlar.
- Yabancı anahtar kısıtlaması: Tablolar arasındaki ilişkileri tanımlayarak referans bütünlüğünü sağlar.
- Kontrol kısıtlaması: Bir alan değerinin belirli bir koşulu karşılamasını sağlar.
Varlık modelinde, veri bütünlüğünü korumak için kısıtlamaları aşağıdaki gibi tanımlayabilirsiniz:
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("username").
Unique(), // Kullanıcı adının tabloda benzersiz olmasını sağlamak için benzersiz kısıtlama.
field.String("email").
Unique(), // E-postanın tabloda benzersiz olmasını sağlamak için benzersiz kısıtlama.
}
}
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("friends", User.Type).
Unique(), // Yabancı anahtar kısıtlaması, başka bir kullanıcıyla benzersiz bir kenar ilişkisi oluşturur.
}
}
Özetle, alan doğrulama ve kısıtlamalar, iyi veri kalitesini sağlamak ve beklenmeyen veri hatalarını önlemek için hayati öneme sahiptir. ent
çerçevesinin sağladığı araçları kullanmak bu süreci daha basit ve güvenilir hale getirebilir.