Question
Is it possible to create a reference without creation of association itself in many-to-many use case?
E.g. I have tables - users, languages and joint table user_languages. languages table is already fulfilled with a list of available languages. When I'm creating a user with languages I don't need to do insertion into languages but I want to create a reference in a joint table only. In gorm v1 such behaviour was achieved by using association_autoupdate:false tag in a model. In gorm v2 method Omit("Languages") also omits reference. Thank you!
Comment From: yzha5
gorm v2
However, even if Omit("Languages") is used, the INSERT INTO `languages`... statement will still be executed
type User struct {
Id int
Languages []Language `gorm:"many2many:language_user"`
}
type Language struct {
Id int
}
When I run
db.Debug().Model(&User{Id: 1}).Omit("Languages").Association("Languages").Append([]Language{{Id: 9},{Id: 10}})
The console printed these two lines of statements
//INSERT INTO `languages` ...
//INSERT INTO `language_user` ...
INSERT INTO `languages` ... I don’t want this because I set the verification in the hook of Language
Comment From: wangeguo
I have the same question
Comment From: devhossamali
I believe this should be considered as a bug not feature_request
Comment From: jinzhu
The latest master support to use the following code to skip the associations itself
db.Omit("Languages.*")
Comment From: jinzhu
Updated the document https://gorm.io/docs/associations.html#Skip-Auto-Create-Update
Comment From: leefernandes
@jinzhu Is this in a tagged release? I came over from this linked issue - https://github.com/go-gorm/gorm/issues/3710
On 1.20.8 I'm still seeing INSERT INTO "languages" inserts when just wanting the association record in the association table to be created with provided IDs, and want gorm to please leave the resource tables alone when making just an m2m association between two existing records.
db.Debug().Model(&User{Id: 1}).Omit("Languages.*").Association("Languages").Append([]Language{{Id: 9},{Id: 10}})
I'm looking for an api method to ONLY create the language_user association table record.
Actual
INSERT INTO "languages"...
INSERT INTO "language_user"...
Expected (Desired?)
INSERT INTO "language_user"...
Comment From: knlambert
@ItsLeeOwen same issue for me. it's easy to find a workaround, but it's misleading since this was working in the previous version.
Comment From: GiancarlosIO
👀
Comment From: inliquid
@jinzhu any updates on last questions?
Comment From: birdycn
同样的问题,append不希望创建,因为忽略了部分非空值,导致append失败
Comment From: devhossamali
This bug is now resolved, please upgrade to v1.21.4 or later releases
Comment From: ngocketit
It's still an issue for me. Such a huge disappointment with Gorm that it can't even handle such a basic use-case
Comment From: ngocketit
I tried all different ways mentioned in the docs but nothing worked. The use case is to add existing records to the many-to-many relationship. Had to resort to raw queries as I didn't want to waste more time on this:
return svc.db.Transaction(func(tx *gorm.DB) error {
for _, userId := range request.Instructors {
if err := tx.Exec("INSERT INTO program_instructors VALUES (?, ?)", program.ID, userId).Error; err != nil {
return err
}
}
return nil
})
Comment From: jinzhu
It's still an issue for me. Such a huge disappointment with Gorm that it can't even handle such a basic use-case
we have tests & users confirmed that works, if it doesn't work for you, create an issue with reproducible PR.
Comment From: tolik505
@ngocketit I'm using v1.21.16 and tx.Omit("Languages.*") works as expected for me. It creates relations in joint table without inserting new records into languages table. Please, check gorm version in your project.
Comment From: ngocketit
It's still an issue for me. Such a huge disappointment with Gorm that it can't even handle such a basic use-case
we have tests & users confirmed that works, if it doesn't work for you, create an issue with reproducible PR.
Thanks for your comment @jinzhu. Maybe I missed something but here is the code I used:
var users []*models.User
if err := svc.db.Where("id IN ? and school_id = ?", request.Instructors, program.SchoolID).Find(&users).Error; err != nil {
return err
}
instructors, err := svc.GetInstructors(program)
if err != nil {
return err
}
instructors = append(instructors, users...)
return svc.db.Model(program).Omit("Instructors").Association("Instructors").Replace(instructors)
That will result in the users being inserted in users table. As the users already exist, it shouldn't be that way.
Then I tried Append instead of Replace:
var users []*models.User
if err := svc.db.Where("id IN ? and school_id = ?", request.Instructors, program.SchoolID).Find(&users).Error; err != nil {
return err
}
return svc.db.Model(program).Omit("Instructors").Association("Instructors").Append(users)
And I got:
reflect: call of reflect.Append on zero Value
/usr/local/go/src/reflect/value.go:221 (0x10ccbe4)
flag.mustBe: panic(&ValueError{methodName(), f.kind()})
/usr/local/go/src/reflect/value.go:2048 (0x10cca0f)
Append: s.mustBe(Slice)
/Users/Workspace/my/go/pkg/mod/gorm.io/gorm@v1.21.16/association.go:354 (0x14ffcbe)
(*Association).saveAssociation.func1.1: fieldValue = reflect.Append(fieldValue, ev)
/Users/Workspace/my/go/pkg/mod/gorm.io/gorm@v1.21.16/association.go:369 (0x15003b3)
(*Association).saveAssociation.func1: appendToFieldValues(reflect.Indirect(rv.Index(i)).Addr())
/Users/Workspace/my/go/pkg/mod/gorm.io/gorm@v1.21.16/association.go:469 (0x14e2521)
(*Association).saveAssociation: appendToRelations(reflectValue, rv, clear && idx == 0)
/Users/Workspace/my/go/pkg/mod/gorm.io/gorm@v1.21.16/association.go:58 (0x14dd4c4)
(*Association).Append: association.saveAssociation( /*clear*/ false, values...)
Gorm version: v1.21.16
Comment From: ngocketit
@ngocketit I'm using v1.21.16 and tx.Omit("Languages.*") works as expected for me. It creates relations in joint table without inserting new records into languages table. Please, check gorm version in your project.
Thank you @tolik505 ! Using .Omit("Instructors.*") indeed works for Replace. However, I still get reflect: call of reflect.Append on zero Value with Append
Comment From: andrew-atwood-infinitusai
@ngocketit I was trying to do this same thing and got the same error, and eventually figured it out. Well, I figured out that specific error, I have yet to figure out how to skip the INSERT which is the whole thing, but it's a step forward.
The reflect: call of reflect.Append on zero Value error is due to your parent User model not having an existing slice on the Languages field. The Assocation.Append method tries to actually append the given entries to the parent model before doing anything with query building, as silly as it sounds.
I don't know when, outside of procedural example code, you would actually have that array on your User when doing a simple update by IDs, but alas!
Comment From: linktomarkdown
gorm v2 However, even if
Omit("Languages")is used, theINSERT INTO `languages`...statement will still be executed
``go type User struct { Id int Languages []Languagegorm:"many2many:language_user"` }type Language struct { Id int } ```
When I run
go db.Debug().Model(&User{Id: 1}).Omit("Languages").Association("Languages").Append([]Language{{Id: 9},{Id: 10}})The console printed these two lines of statements
//INSERT INTO `languages` ... //INSERT INTO `language_user` ...
INSERT INTO `languages` ...I don’t want this because I set the verification in the hook ofLanguage
thank you very much. you save my life.