doujinyi1267 2014-08-05 15:14
浏览 60
已采纳

如何在Revel Controller中访问Gorm?

let me start by saying these are my first couple days of toying around in Go.

I'm trying to use the Revel framework with Gorm like this:

app/controllers/gorm.go

package controllers

import (
    "fmt"
    "go-testapp/app/models"

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

var DB gorm.DB

func InitDB() {
    var err error
    DB, err = gorm.Open("mysql", "root:@/go-testapp?charset=utf8&parseTime=True")
    if err != nil {
        panic(err)
    }
    DB.LogMode(true)
    DB.AutoMigrate(models.User{})
}

type GormController struct {
    *revel.Controller
    DB *gorm.DB
}

app/controller/app.go

package controllers

import (
    "fmt"
    "go-bingo/app/models"

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

type App struct {
    GormController
}

func (c App) Index() revel.Result {
    user := models.User{Name: "Jinzhu", Age: 18}

    fmt.Println(c.DB)
    c.DB.NewRecord(user)

    c.DB.Create(&user)

    return c.RenderJson(user)
}

After running it results in:

runtime error: invalid memory address or nil pointer dereference on line 19 c.DB.NewRecord(user)

It successfully creates the datatables with automigrate, but I have no idea how I should use Gorm in my controller.

Any hints in the right direction?

  • 写回答

4条回答 默认 最新

  • dongou4052 2014-09-22 14:19
    关注

    Important note

    it's just replacement for GORP of original example of the Revel. And it comes with some pitfalls of the origin. This answer can be used as drop-in replacement for the original one. But it doesn't solve the pitfalls.

    Please, take a look comments of this unswer and @MaxGabriel's answer that solves the pitfalls.

    I'd recommend to use @MaxGabriel's solution to protect you application against some kinds of slow-* DDoS attacks. And to reduce (in some cases) DB pressure.

    Original answer

    @rauyran rights, you have to invoke InitDB inside init function (into controllers package).

    Full example here (too much):

    Tree

    /app
        /controllers
          app.go
          gorm.go
          init.go
        /models
          user.go
    [...]
    

    user.go

    // models/user.go
    package models
    
    import  "time" // if you need/want
    
    type User struct {          // example user fields
        Id                    int64
        Name                  string
        EncryptedPassword     []byte
        Password              string      `sql:"-"`
        CreatedAt             time.Time
        UpdatedAt             time.Time
        DeletedAt             time.Time     // for soft delete
    }
    

    gorm.go

    //controllers/gorm.go
    package controllers
    
    import (
        "github.com/jinzhu/gorm"
        _ "github.com/lib/pq" // my example for postgres
        // short name for revel
        r "github.com/revel/revel"
        // YOUR APP NAME
        "yourappname/app/models"
        "database/sql"
    )
    
    // type: revel controller with `*gorm.DB`
    // c.Txn will keep `Gdb *gorm.DB`
    type GormController struct {
        *r.Controller
        Txn *gorm.DB
    }
    
    // it can be used for jobs
    var Gdb *gorm.DB
    
    // init db
    func InitDB() {
        var err error
        // open db
        Gdb, err = gorm.Open("postgres", "user=uname dbname=udbname sslmode=disable password=supersecret")
        if err != nil {
            r.ERROR.Println("FATAL", err)
            panic( err )
        }
        Gdb.AutoMigrate(&models.User{})
        // unique index if need
        //Gdb.Model(&models.User{}).AddUniqueIndex("idx_user_name", "name")
    }
    
    
    // transactions
    
    // This method fills the c.Txn before each transaction
    func (c *GormController) Begin() r.Result {
        txn := Gdb.Begin()
        if txn.Error != nil {
            panic(txn.Error)
        }
        c.Txn = txn
        return nil
    }
    
    // This method clears the c.Txn after each transaction
    func (c *GormController) Commit() r.Result {
        if c.Txn == nil {
            return nil
        }
        c.Txn.Commit()
        if err := c.Txn.Error; err != nil && err != sql.ErrTxDone {
            panic(err)
        }
        c.Txn = nil
        return nil
    }
    
    // This method clears the c.Txn after each transaction, too
    func (c *GormController) Rollback() r.Result {
        if c.Txn == nil {
            return nil
        }
        c.Txn.Rollback()
        if err := c.Txn.Error; err != nil && err != sql.ErrTxDone {
            panic(err)
        }
        c.Txn = nil
        return nil
    }
    

    app.go

    package controllers
    
    import(
        "github.com/revel/revel"
        "yourappname/app/models"
    )
    
    type App struct {
        GormController
    }
    
    func (c App) Index() revel.Result {
        user := models.User{Name: "Jinzhup"}
        c.Txn.NewRecord(user)
        c.Txn.Create(&user)
        return c.RenderJSON(user)
    }
    

    init.go

    package controllers
    import "github.com/revel/revel"
    
    func init() {
        revel.OnAppStart(InitDB) // invoke InitDB function before
        revel.InterceptMethod((*GormController).Begin, revel.BEFORE)
        revel.InterceptMethod((*GormController).Commit, revel.AFTER)
        revel.InterceptMethod((*GormController).Rollback, revel.FINALLY)
    }
    

    As you can see, it's like Revel's Booking modified for GORM.

    Works fine for me. Result:

    {
      "Id": 5,
      "Name": "Jinzhup",
      "EncryptedPassword": null,
      "Password": "",
      "CreatedAt": "2014-09-22T17:55:14.828661062+04:00",
      "UpdatedAt": "2014-09-22T17:55:14.828661062+04:00",
      "DeletedAt": "0001-01-01T00:00:00Z"
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)