GORM Playground Link

Here is my playground link: https://github.com/go-gorm/playground/pull/596. I've reproduced the models.go and main_test.go below:

main_test.go:

func TestGORM(t *testing.T) {
    user := User{Name: "jinzhu"}

    DB.Create(&user)

    var result User
    if err := DB.First(&result, user.ID).Error; err != nil {
        t.Errorf("Failed, got error: %v", err)
    }

    familiar := Familiar{Name: "fam"}
    familiarIDBefore := familiar.Id
    DB.Create(&familiar)
    familiarIDAfter := familiar.Id
    if familiarIDBefore == familiarIDAfter {
        t.Errorf("Familiar ID should be created")
    }

    meeting := Meeting{IsLive: true}
    DB.Create(&meeting)
    familiars := []Familiar{familiar}
    meetingFamiliars := meeting.Familiars
    if len(meetingFamiliars) > 0 {
        t.Errorf("Meeting should not have any familiars yet")
    }

    DB.Model(&meeting).Association("Familiars").Append(familiars)
    meetingFamiliars = meeting.Familiars
    if len(meetingFamiliars) != 1 {
        t.Errorf("Meeting should have a familiar now")
    }

    familiarInMeetingID := meetingFamiliars[0].Id

    familiarIDAfterMeetingAdd := familiar.Id
    if familiarIDAfterMeetingAdd != familiarIDAfter {
        t.Errorf("Familiar ID should not be changed")
    }

    if familiarInMeetingID != familiarIDAfter {
        t.Errorf("Familiar ID should be the same. Meeting familiar ID: %v, familiar ID: %v", familiarInMeetingID, familiarIDAfter)
    }
}

models.go:

type Language struct {
    Code string `gorm:"primarykey"`
    Name string
}

type Meeting struct {
    gorm.Model
    Id          string     `gorm:"type:uuid;primaryKey" json:"id"`
    IsLive      bool       `json:"isLive"`
    CompletedAt time.Time  `json:"completedAt"`
    Familiars   []Familiar `gorm:"many2many:familiar_meetings;"`
}

func (m *Meeting) BeforeCreate(tx *gorm.DB) (err error) {
    // UUID version 4
    m.Id = uuid.NewString()
    return
}

type Familiar struct {
    gorm.Model
    Id       string    `gorm:"type:uuid;primaryKey" json:"id"`
    Meetings []Meeting `gorm:"many2many:familiar_meetings;"`
    Name     string    `json:"name"`
}

func (f *Familiar) BeforeCreate(tx *gorm.DB) (err error) {
    // UUID version 4
    f.Id = uuid.NewString()
    return
}

Description

The issue is that BeforeCreate is called on children being added to a many2many. Because I'm using BeforeCreate to do uuids, this is changing the Id of the object being added to the many2many.

Besides the bug, is there a better way to do what I'm trying to do? I'm new to gorm.

Comment From: github-actions[bot]

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking

Comment From: Poisonwind

I have the same problem. After "BeforeCreate" was added to base model (id). Gorm started to create all child models with base model (id) in it or change its uuid.

Comment From: black-06

try this model

type Familiar struct {
    ID       string    `gorm:"type:uuid;primaryKey" json:"id"`
    Meetings []Meeting `gorm:"many2many:familiar_meetings;"`
    Name     string    `json:"name"`
}

func (f *Familiar) BeforeCreate(tx *gorm.DB) (err error) {
    if f.ID == "" {
        // UUID version 4
        f.ID = uuid.NewString()
    }
    return
}

Association.Append will try INSERT ... ON CONFLICT DO NOTHING. So we need to keep primaryKey if it already exists.

Comment From: cinjon

Are you suggesting dropping the gorm.Model from the model definition? That's the main change I see here.

Comment From: black-06

Are you suggesting dropping the gorm.Model from the model definition? That's the main change I see here.

it's if f.ID == ""

Comment From: black-06

Or try to skip auto create/update, https://gorm.io/docs/associations.html#Skip-Auto-Create-x2F-Update