Let's Go پاسخ‌های مبتنی بر پایگاه داده › طراحی مدل پایگاه داده
قبلی · فهرست · بعدی
فصل 4.5.

طراحی مدل پایگاه داده

در این فصل، ما قصد داریم یک مدل پایگاه داده برای پروژه خود ترسیم کنیم.

اگر از اصطلاح مدل خوشتان نمی‌آید، ممکن است بخواهید آن را به عنوان یک لایه سرویس یا لایه دسترسی به داده در نظر بگیرید. هر چه ترجیح می‌دهید آن را بنامید، ایده این است که کد کار با MySQL را در یک پکیج جدا از بقیه برنامه خود کپسوله کنیم.

برای حالا، یک مدل پایگاه داده اسکلتی ایجاد می‌کنیم و آن را به گونه‌ای می‌کنیم که کمی داده ساختگی برگرداند. کار زیادی انجام نمی‌دهد، اما می‌خواهم الگو را قبل از ورود به جزئیات پرس‌وجوهای SQL توضیح دهم.

خوب است؟ پس بیایید ادامه دهیم و یک دایرکتوری جدید internal/models حاوی یک فایل snippets.go ایجاد کنیم:

$ mkdir -p internal/models
$ touch internal/models/snippets.go
04.05-01.png

بیایید فایل internal/models/snippets.go را باز کنیم و یک ساختار جدید Snippet برای نمایش داده‌های یک snippet فردی اضافه کنیم، همراه با یک نوع SnippetModel با متدهای روی آن برای دسترسی و دستکاری snippetها در پایگاه داده ما. مانند این:

File: internal/models/snippets.go
package models

import (
    "database/sql"
    "time"
)

// Define a Snippet type to hold the data for an individual snippet. Notice how
// the fields of the struct correspond to the fields in our MySQL snippets
// table?
type Snippet struct {
    ID      int
    Title   string
    Content string
    Created time.Time
    Expires time.Time
}

// Define a SnippetModel type which wraps a sql.DB connection pool.
type SnippetModel struct {
    DB *sql.DB
}

// This will insert a new snippet into the database.
func (m *SnippetModel) Insert(title string, content string, expires int) (int, error) {
    return 0, nil
}

// This will return a specific snippet based on its id.
func (m *SnippetModel) Get(id int) (Snippet, error) {
    return Snippet{}, nil
}

// This will return the 10 most recently created snippets.
func (m *SnippetModel) Latest() ([]Snippet, error) {
    return nil, nil
}

استفاده از SnippetModel

برای استفاده از این مدل در handlerهای خود، باید یک ساختار جدید SnippetModel در تابع main() خود ایجاد کنیم و سپس آن را به عنوان یک وابستگی از طریق ساختار application تزریق کنیم — دقیقاً همانطور که با سایر وابستگی‌های خود داریم.

اینطور است:

File: cmd/web/main.go
package main

import (
    "database/sql"
    "flag"
    "log/slog"
    "net/http"
    "os"

    // Import the models package that we just created. You need to prefix this with
    // whatever module path you set up back in chapter 02.01 (Project Setup and Creating
    // a Module) so that the import statement looks like this:
    // "{your-module-path}/internal/models". If you can't remember what module path you 
    // used, you can find it at the top of the go.mod file.
    "snippetbox.alexedwards.net/internal/models" 

    _ "github.com/go-sql-driver/mysql"
)

// Add a snippets field to the application struct. This will allow us to
// make the SnippetModel object available to our handlers.
type application struct {
    logger   *slog.Logger
    snippets *models.SnippetModel
}

func main() {
    addr := flag.String("addr", ":4000", "HTTP network address")
    dsn := flag.String("dsn", "web:pass@/snippetbox?parseTime=true", "MySQL data source name")
    flag.Parse()

    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

    db, err := openDB(*dsn)
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }
    defer db.Close()

    // Initialize a models.SnippetModel instance containing the connection pool
    // and add it to the application dependencies.
    app := &application{
        logger:   logger,
        snippets: &models.SnippetModel{DB: db},
    }

    logger.Info("starting server", "addr", *addr)

    err = http.ListenAndServe(*addr, app.routes())
    logger.Error(err.Error())
    os.Exit(1)
}

...

اطلاعات اضافی

مزایای این ساختار

اگر یک قدم به عقب بردارید، ممکن است بتوانید چند مزیت از راه‌اندازی پروژه خود به این روش ببینید: