Maison  >  Article  >  développement back-end  >  Comment renvoyer une entité imbriquée après la création d'un nouvel objet ?

Comment renvoyer une entité imbriquée après la création d'un nouvel objet ?

PHPz
PHPzavant
2024-02-10 21:40:15538parcourir

Comment renvoyer une entité imbriquée après la création dun nouvel objet ?

En PHP, comment renvoyer des entités imbriquées après la création d'un nouvel objet est une question courante. Lorsque nous devons créer un nouvel objet dans une classe et l'utiliser comme attribut d'une autre entité, nous devons prêter attention à certaines techniques et méthodes. Tout d’abord, nous pouvons créer un nouvel objet dans le constructeur de la classe et l’attribuer à la propriété. Nous pouvons ensuite utiliser le mot-clé $this pour référencer l'objet actuel et accéder à ses propriétés. De plus, nous pouvons également utiliser des méthodes statiques ou des modèles d'usine pour créer de nouveaux objets et les renvoyer à l'appelant. Quelle que soit la méthode utilisée, la clé pour renvoyer des entités imbriquées est de gérer correctement les relations entre les objets et de garantir qu'ils interagissent et transmettent correctement les données entre les entités. Grâce à ces méthodes, nous pouvons facilement créer et renvoyer des objets d'entité imbriqués en PHP.

Contenu des questions

Modèle account 包含嵌套结构 - currencyuser

Lorsque je crée une nouvelle instance de account dans la base de données et que je la renvoie ensuite dans la réponse, l'entité imbriquée est vide :

type account struct {
    basemodel
    name       string          `gorm:"size:64;not null" json:"name"`
    balance    decimal.decimal `gorm:"type:decimal(16, 2);default:0;not null;" json:"balance"`
    userid     int             `gorm:"not null" json:"-"`
    user       user            `gorm:"foreignkey:userid" json:"user"`
    currencyid int             `gorm:"not null" json:"-"`
    currency   currency        `gorm:"foreignkey:currencyid" json:"currency"`
}

type createaccountbody struct {
    name       string          `json:"name" binding:"required"`
    balance    decimal.decimal `json:"balance"`
    currencyid int             `json:"currency_id" binding:"required"`
}

func createaccount(ctx *gin.context) {
    body := createaccountbody{}

    if err := ctx.bind(&body); err != nil {
        log.println("error while binding body:", err)
        ctx.json(
            http.statusbadrequest,
            gin.h{"error": "wrong request parameters"},
        )
        return
    }

    account := account {
        name:       body.name,
        balance:    body.balance,
        currencyid: body.currencyid,
        userid:     1,
    }
    
    if result := db.db.create(&account); result.error != nil {
        log.println("unable to create an account:", result.error)
    }    

    ctx.json(http.statuscreated, gin.h{"data": account})
}


Pour éviter ce problème, j'utilise une requête distincte pour actualiser les variables du compte :

db.DB.Create(&account)
db.DB.Preload("User").Preload("Currency").Find(&account, account.ID)
ctx.JSON(http.StatusCreated, gin.H{"data": account})

Est-ce le moyen le plus efficace et le plus correct d'obtenir les résultats souhaités ?

Solution

Je vais partager avec vous comment je gère habituellement cette situation. Tout d’abord, permettez-moi de partager le code.

main.go Fichiers

package main

import (
    "context"

    "gogindemo/handlers"

    "github.com/gin-gonic/gin"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var (
    db  *gorm.db
    ctx *gin.context
)

func init() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
    var err error
    db, err = gorm.open(postgres.open(dsn), &gorm.config{})
    if err != nil {
        panic(err)
    }

    db.automigrate(&handlers.currency{})
    db.automigrate(&handlers.user{})
    db.automigrate(&handlers.account{})
}

func adddb() gin.handlerfunc {
    return func(ctx *gin.context) {
        ctx.request = ctx.request.withcontext(context.withvalue(ctx.request.context(), "db", db))
        ctx.next()
    }
}

func main() {
    db.create(&handlers.user{id: 1, name: "john doe"})
    db.create(&handlers.user{id: 2, name: "mary hut"})
    db.create(&handlers.currency{id: 1, name: "eur"})
    db.create(&handlers.currency{id: 2, name: "usd"})

    r := gin.default()
    r.post("/account", adddb(), handlers.createaccount)

    r.run()
}

Ici, je viens d'ajouter le code pour amorcer l'objet de base de données et d'y ajouter des données factices.

handlers/handlers.go Fichiers

package handlers

import (
    "net/http"

    "github.com/gin-gonic/gin"
    "github.com/shopspring/decimal"
    "gorm.io/gorm"
)

type User struct {
    Id   int
    Name string
}

type Currency struct {
    Id   int
    Name string
}

type Account struct {
    Id         int
    Name       string          `gorm:"size:64;not null" json:"name"`
    Balance    decimal.Decimal `gorm:"type:decimal(16, 2);default:0;not null;" json:"balance"`
    UserID     int             `gorm:"not null" json:"-"`
    User       User            `gorm:"foreignKey:UserID" json:"user"`
    CurrencyID int             `gorm:"not null" json:"-"`
    Currency   Currency        `gorm:"foreignKey:CurrencyID" json:"currency"`
}

type CreateAccountBody struct {
    Name       string          `json:"name" binding:"required"`
    Balance    decimal.Decimal `json:"balance"`
    CurrencyID int             `json:"currency_id" binding:"required"`
}

func CreateAccount(c *gin.Context) {
    db, ok := c.Request.Context().Value("DB").(*gorm.DB)
    if !ok {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"})
        return
    }
    var accountReq CreateAccountBody
    if err := c.BindJSON(&accountReq); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "wrong request body payload"})
        return
    }

    // create Account & update the "account" variable
    account := Account{Name: accountReq.Name, Balance: accountReq.Balance, CurrencyID: accountReq.CurrencyID, UserID: 1}
    db.Create(&account).Preload("Currency").Preload("User").Find(&account, account.Id)

    c.IndentedJSON(http.StatusCreated, account)
}

Dans ce fichier, je communique en fait avec la base de données en le faisant dans context 中传递的 db . Maintenant, revenons à votre question.
Si la relation entre devise//compte et utilisateur/currency//account 和 user/account 之间的关系是 1:1 类型,那么,您应该依赖 preload 子句。这将在单独的查询中加载相关实体,而不是将其添加到 inner join est de type 1:1 , alors vous devez vous fier à la clause preload. Cela chargera les entités associées dans une requête distincte plutôt que de les ajouter à la clause inner join.

S'il vous plaît dites-moi si cela résout votre problème, merci !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer