Lazy loading

توی جنگو این مفهوم هست و کاربردش اینه تا زمانی که به داده نیاز نیست ، درخواست سمت دیتابیس نمی ره ، یکی از نتایج این مفهوم اینه زمانی که با orm می خواهیم join بزنیم ، میشه با این ۲ متد زیر تمامی دادهد هایی که در چند تیبل وجود دارد را یک جا فچ کرد

  • select_related
  • prefetch_related

اما در GORM راه حل استفاده از Preload هست

اگر از Preload استفاده نکنیم تنها id های تیبل سفارش رو داریم

type User struct {
  gorm.Model
  Orders []Order
}
type Order struct {
  gorm.Model
  UserID uint
}
 
var users []User
 
// Lazy: no orders fetched
db.Find(&users)
 
 
// Eager load orders via separate query
// توی این حالت ۲ بار کوییری زده میشه
 
db.Preload("Orders").Find(&users)
 
 
SELECT * FROM `users`;
 
SELECT * 
FROM `orders` 
WHERE `orders`.`user_id` IN (1,2,3, …);
 
 
 
var users []User
if err := db.Preload("Orders").Find(&users).Error; err != nil {
    log.Fatal(err)
}
 
// Now each users[i].Orders is filled:
for _, u := range users {
    fmt.Printf("User %d (%s) has %d orders:\n", u.ID, u.Name, len(u.Orders))
    for _, o := range u.Orders {
        fmt.Printf("  • Order %d: total=%.2f\n", o.ID, o.Total)
    }
}
 
 
// Or via JOIN
// زمانی که از جویین استفاده می کنیم تنها یک کوییری زده میشه
 
db.Joins("Orders").Find(&users)
 
 
SELECT
  `users`.`id`,
  `users`.`name`,
  `orders`.`id`   AS `orders__id`,
  `orders`.`user_id` AS `orders__user_id`,
  `orders`.`total` AS `orders__total`
FROM `users`
LEFT JOIN `orders` ON `orders`.`user_id` = `users`.`id`;
 
// اما بدیش اینه که برای سلکت جویین باید خودمون بشینیم  کلی استرینگ بنویسیم و کد بشدت کثیف میشه
 
 
// helper struct to capture flattened columns
type UserOrderRow struct {
    UserID    uint
    UserName  string
    OrderID   uint
    OrderTotal float64
}
 
var rows []UserOrderRow
err := db.
    Model(&User{}).
    Select("users.id   AS user_id, " +
           "users.name AS user_name, " +
           "orders.id  AS order_id, " +
           "orders.total AS order_total").
    Joins("LEFT JOIN orders ON orders.user_id = users.id").
    Scan(&rows).
    Error
if err != nil {
    log.Fatal(err)
}
 
// Now rows is a flat list; group them in Go if you want per-user slices
grouped := make(map[uint][]Order)
for _, r := range rows {
    o := Order{ID: r.OrderID, UserID: r.UserID, Total: r.OrderTotal}
    grouped[r.UserID] = append(grouped[r.UserID], o)
}
 
// iterate users and their orders
for userID, orders := range grouped {
    fmt.Printf("User %d has %d orders:\n", userID, len(orders))
    for _, o := range orders {
        fmt.Printf("  • Order %d: total=%.2f\n", o.ID, o.Total)
    }
}
 
 

جمع بندی :

برای تمییزی حاضرم ۲ کوییری بزنیم اما کد تمییز تر هندل شه و در نهایت از Preload استفاده می کنم