Gorm: String primary keys and associations

Created on 12 Aug 2015  路  2Comments  路  Source: go-gorm/gorm

My models uses random strings as Primery Key which is generated using _BeforeCreate_ callback. Everything works, but when I try to persist an Object with its Associations I'm getting this error:

[0.71ms]  INSERT INTO "hands" ("id","name") VALUES ('75','left') RETURNING "hands"."id"
pq: null value in column "id" violates not-null constraint
pq: null value in column "id" violates not-null constraint
[1.46ms]  INSERT INTO "fingers" ("hand_id","name") VALUES ('75','a') RETURNING "fingers"."id"

So it seem that GORM is not assigning the ID to Fingers when performing the INSERT

This is a sample code that reproduce the issue:

package main

import (
    "fmt"
    "math/rand"
    "time"

    "github.com/jinzhu/gorm"
    _ "github.com/lib/pq"
)

func randomString() string {
    rand.Seed(time.Now().UnixNano())
    return fmt.Sprintf("%d", rand.Intn(100))
}

type Finger struct {
    ID     string `gorm:"primary_key"`
    HandID string
    Name   string
}

func (f *Finger) BeforeCreate() error {
    r := randomString()
    f.ID = r
    return nil
}

type Hand struct {
    ID      string `gorm:"primary_key"`
    Name    string
    Fingers []Finger
}

func (h *Hand) BeforeCreate() error {
    r := randomString()
    h.ID = r
    return nil
}

func main() {
    db, _ := gorm.Open("postgres", "user=postgres sslmode=disable")
    db.Debug().AutoMigrate(&Hand{}, &Finger{})

    h := &Hand{
        Name: "left",
        Fingers: []Finger{
            Finger{Name: "a"}, Finger{Name: "b"},
        },
    }
    db.Debug().Create(h)
}

I'm I doing something wrong?

question

Most helpful comment

Please reopen this issue as it is not fixed , nor is it documented anywhere. I've just spent a whole day on this.

I had a function very similar to this one:

func (h *Hand) BeforeCreate() error {
    h.ID = someRandomID
    return nil
}

Having to set the value via scope.setColumn is not documented anywhere , just referenced in some places , but no clear indication on why you should do it that way.

Having the function applied to a pointer made me think that I am supposed to modify that object , as if that object was the final object that will get sent to the DB. That was confusing.

Thanks
Mircea

All 2 comments

Hi @gchaincl

It needs to be written like this:

func (h *Hand) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", randomString())
    return nil
}

In callbacks, if you want to update any columns to database, has to use SetColumn, this wasn't documented before, will add this to the v1 release.

Thank you.

Please reopen this issue as it is not fixed , nor is it documented anywhere. I've just spent a whole day on this.

I had a function very similar to this one:

func (h *Hand) BeforeCreate() error {
    h.ID = someRandomID
    return nil
}

Having to set the value via scope.setColumn is not documented anywhere , just referenced in some places , but no clear indication on why you should do it that way.

Having the function applied to a pointer made me think that I am supposed to modify that object , as if that object was the final object that will get sent to the DB. That was confusing.

Thanks
Mircea

Was this page helpful?
0 / 5 - 0 ratings

Related issues

youtwo123 picture youtwo123  路  3Comments

alanyuen picture alanyuen  路  3Comments

hypertornado picture hypertornado  路  3Comments

leebrooks0 picture leebrooks0  路  3Comments

corvinusy picture corvinusy  路  3Comments