Как объединить запросы - PullRequest
0 голосов
/ 11 марта 2019

Я пишу страницу, где отображается список постов блога, с нумерацией страниц. Я использую GORM с Go 1.12. У каждого блога есть автор под названием Пользователь, и этот пользователь может содержать некоторую дополнительную информацию о сотруднике, если это необходимо. (например, введение, название функции, ...)

Мои модели:

type EmployeeInfo struct {
    UserID    uint   `gorm:"not null;unique"`
    Title     string `gorm:"not null"`
    Intro     string `gorm:""`
}

type User struct {
    gorm.Model

    Username  string    `gorm:"unique;not null"`
    Password  string    `gorm:"unique;not null"`

    FirstName string    `gorm:"not null"`
    LastName  string    `gorm:"not null"`

    Company   Company   `gorm:"not null"`

    Role      string    `gorm:"not null;default:user"`
}

type BlogPost struct {
    gorm.Model

    Title     string    `gorm:"not null"`
    Slug      string    `gorm:"unique;not null;index"`
    Intro     string    `gorm:"not null"`
    Text      string    `gorm:"not null"`
    Category  string    `gorm:"not null"`
    PictureUrl string   `gorm:"not null"`
    Author    User      `gorm:"not null"`
    AuthorID  uint      `gorm:"not null"`
}

Мой код выглядит следующим образом:

func (hh *BlogIndexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // set desired language
    language.SetLanguage(r)

    // set title
    hh.data.Title = fmt.Sprintf(
        "%s - %s",
        language.Translate("blog", nil, false),
        language.Translate("product", nil, false),
    )

    // get current page
    hh.data.Page = 0
    if intPage, err := strconv.Atoi(r.URL.Query().Get(pageQueryName)); err != nil && intPage >= 0 {
        hh.data.Page = intPage
    }

    // get max page number
    hh.data.MaxPage = 1
    var totalPosts int
    if err := hh.database.Model(&models.BlogPost{}).Count(&totalPosts).Error; err != nil {
        totalPosts = 1
    } else {
        hh.data.MaxPage = roundUp(float64(totalPosts / PostsPerPage))
    }

    // if page > maxPage, set it right
    if hh.data.Page > hh.data.MaxPage {
        hh.data.Page = hh.data.MaxPage
    }

    // fetch blog posts
    if err := hh.database.
        Preload("Author").
        Order("created_at DESC").
        Offset(PostsPerPage * hh.data.Page).
        Limit(PostsPerPage).
        Find(&hh.data.Posts).
        Error; err != nil {

        log.Errorf(appengine.NewContext(r), "could not get posts: %v", err)
    }

    // set cacheable
    system.SetCacheable(w, system.CacheTime1Day)

    // send webpage
    hh.template.Render("blog/index", w, hh.data)
}

Однако запрос запускает 3 разных запроса:

[2019-03-11 19:51:52]  [29.55ms]  SELECT count(*) FROM "blog_posts"  WHERE "blog_posts"."deleted_at" IS NULL
[0 rows affected or returned ]

[2019-03-11 19:51:52]  [27.50ms]  SELECT * FROM "blog_posts"  WHERE "blog_posts"."deleted_at" IS NULL ORDER BY created_at DESC LIMIT 9 OFFSET 0
[1 rows affected or returned ]

[2019-03-11 19:51:52]  [49.86ms]  SELECT * FROM "users"  WHERE "users"."deleted_at" IS NULL AND (("id" IN ('58')))

Есть ли способ объединить их с GORM? Я хотел бы оптимизировать их, как и при ручном запросе.

1 Ответ

0 голосов
/ 12 марта 2019

GORM не поддерживает уровень базы данных JOIN на Preload. У вас есть два варианта:

  • либо используйте Preload и согласитесь с тем, что он выполняет дополнительный запрос для извлечения связанных данных (что не должно быть проблемой, если у вас нет большой нагрузки на вашем сервере)
  • или вы можете написать свой собственный запрос Raw Sql , используя JOIN и обработать все в одном запросе, а затем сопоставить данные со структурой.
...