Gorm: UPDATE instead of INSERT when nested struct has string primary key

Created on 6 Apr 2016  路  8Comments  路  Source: go-gorm/gorm

Hello,

When I try to call the "Create" function on a struct with nested struct which has string primary key (that I have to init manualy), according to the .debug(), GORM do an UPDATE instead of an INSERT in SQL.

Here the complete file (which could be usefull for some guy like me discovering GORM :) )

gormSample.txt

Best regards

Most helpful comment

Has anyone solved this for structs that don't use gorm.Model and want to set the ID themselves?

All 8 comments

In addition, I know about the way to generate an ID throw the BeforeCreate function..
However, in my case, I want to put a key manually

My problem was : I had a struct which primary key was also a foreign key.
That was a problem because GORM don't manage this problem directly.

As a solution, I must have add a field (sql ignored) in my struct, like this :

type WizardContent struct {
ID string gorm:"primary_key;column:ID"
//My other fields
ContentID string sql:"-" gorm:"column:ID"
}

And add a BeforeCreate method (standard in Gorm) to put the content of my Content field into the ID field (to bypass the UPDATE and force the INSERT) :

func (u *WizardContent) BeforeCreate(scope *gorm.Scope) error {
scope.SetColumn("ID", u.ContentID)
return nil
}

After that, when I tried to Find my Item into a Preload, I was facing another problem :
Gorm automaticaly put the ID of my top struct as primary key of my targeted one.

To avoid this behaviour, I have had to create an AfterFind method (standard in Gorm) to set tje ID field before GORM did his automatic fill :

func (u *WizardContent) AfterFind(scope *gorm.Scope) error {
u.ContentID = u.ID
return nil
}

With this method, I'm able to manage a struct with one-to-one association when the child PK is also the FK to the parent struct.

I hope it'll help someone :)

...Over

i'm having the same problem.
however my case are fairly easy, with one struct having nested sturct slice. after i call create, it will create a insert sql for the main struct. then it will update the nested struct when there is nothing in the db...

type Video struct {
    Index    string `json:"-" gorm:"type:varchar(100);not null"`
    Title    string `json:"videoname,omitempty" gorm:"type:varchar(100);not null"`
    Id       string `json:"cloudname,omitempty" gorm:"type:varchar(100);not null"`
    ImageUrl string `json:"imageurl,omitempty" gorm:"type:varchar(100);not null"`
    VideoUrl string `json:"videourl,omitempty" gorm:"type:varchar(100);not null"`
    Detail   string `json:"detail,omitempty" gorm:"type:varchar(100); not null"`
}

type Series struct {
    Id     string  `json:"subject_id,omitempty" gorm:"type:varchar(100)"`
    Title  string  `json:"subject,omitempty" gorm:"type:varchar(100);not null"`
    Videos []Video `json:"details,omitempty" gorm:"ForeignKey:Index;AssociationForeignKey:Id"`
}

I'm having a similar issue. I have a one-to-many relationship, where both tables have a string primary key, like this:

type Profile struct {
  ID string `gorm:"primary_key;unique_index"`
  Names []Name
}

type Name struct {
  ID string `gorm:"primary_key;unique_index"`
  ProfileID string
  Value string
}

Since these IDs are not auto incrementing, I added a BeforeCreate callback to set a UUID value for the ID:

func (p *Profile) BeforeCreate() (err error) {
    p.ID = uuid.NewV4().String()
    return nil
}

func (n *Name) BeforeCreate() (err error) {
    n.ID = uuid.NewV4().String()
    return nil
}

When I call db.Create(&profile) the INSERT statement for Profile has an ID value, but the one for Name does not.

Similar issue happened to me. Solved this by adding gorm.Model to every struct definition.

Has anyone solved this for structs that don't use gorm.Model and want to set the ID themselves?

should works now.

package main

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    _ "github.com/lib/pq"
    _ "github.com/mattn/go-sqlite3"
)

var db *gorm.DB

type Image struct {
    Name     string `gorm:"primary_key"`
    Status   string
    Versions []ImageVersion
}

type ImageVersion struct {
    SHA        string `gorm:"primary_key"`
    ImageName  string `gorm:index`
    LayerCount int
}

func init() {
    var err error
    // db, err = gorm.Open("sqlite3", "test.db")
    // db, err = gorm.Open("postgres", "user=username dbname=password sslmode=disable")
    db, err = gorm.Open("mysql", "gorm:gorm@/gorm?charset=utf8&parseTime=True")
    if err != nil {
        panic(err)
    }
    db.LogMode(true)
}

func main() {
    db.DropTable(&Image{}, &ImageVersion{})
    db.AutoMigrate(&Image{}, &ImageVersion{})

    image1 := Image{
        Versions: []ImageVersion{
            {SHA: "111"},
            {SHA: "222"},
        },
    }

    db.Save(&image1)
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

youtwo123 picture youtwo123  路  3Comments

corvinusy picture corvinusy  路  3Comments

Quentin-M picture Quentin-M  路  3Comments

littletwolee picture littletwolee  路  3Comments

bramp picture bramp  路  3Comments