I'm trying to create a belongs to relation between two database tables, using GORM, my code is the following:
type Shop struct {
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
Name string `json:"name" gorm:"not null" validate:"required"`
City string `json:"city" gorm:"not null" validate:"required"`
State string `json:"state" gorm:"not null" validate:"required"`
}
type Employee struct {
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
FirstName string `json:"first_name" gorm:"not null" validate:"required"`
LastName string `json:"last_name" gorm:"not null" validate:"required"`
Email string `json:"email" gorm:"not null;unique" validate:"required,email"`
Password string `json:"password" gorm:"not null" validate:"required"`
Active bool `json:"active" gorm:"not null;default:false"`
ShopId uuid.UUID `json:"shop_id" gorm:"type:uuid"`
Shop Shop `gorm:"foreignKey:ShopID"`
}
When I run the migrations, this error pops up:
[error] invalid field found for struct .../.../.../api/models.Employee's field Shop: define a valid foreign key for relations or implement the Valuer/Scanner interface
I've found some references using number primary keys and they seem to work fine, but I can't find any solution to work with uuids...
I'm not sure, but what I understand of the message error is that the type uuid.UUID doesn't have implemented the methods for the interfaces Valuer and Scanner.
You should create your own type UUID, which can be something like this:
type UUID uuid.UUID
func(id UUID) Value() (driver.Value, error) {
return id.String(), nil
}
func (id *UUID) Scan(value interface{}) error {
dbID, ok := value.(string)
if !ok {
return errors.New("id scan: invalid value")
}
*e = uuid.MustParse(dbID)
return nil
}
And use it on your struct's definitions:
type Shop struct {
ID UUID `json:"id" gorm:"primaryKey;type:uuid"`
//...
}
Related
Always got an error when I add the relationship to the User in GitUser struct.
type GitUser struct {
ID uint `json:"id" gorm:"primaryKey"`
ExternalID string
JobID uint
UserID uint
User User `gorm:"foreignKey:UserID;references:ID"`
Job Job `gorm:"foreignKey:JobID;references:ID"`
}
type User struct {
ID uint `json:"id" gorm:"primaryKey"`
ExternalId *string
Username string
Email string
Name string
HashedPassword *string
AvatarUrl *string
IsAdmin bool
LastSignInAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
IsArchived bool
GitUser []GitUser
}
I'm trying to make a mutual relationship between User and GitUser
I have database structure:
type User struct {
db.Base
Username string `gorm:"unique;not null" json:"username"`
Password string `gorm:"not null" json:"password"`
FullName string `gorm:"not null" json:"full_name"`
Email string `gorm:"unique;not null" json:"email"`
}
And Account DB structure:
type Account struct {
db.Base
UserID uuid.UUID `gorm:"not null" json:"user_id"`
User user.User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"user"`
Name string `gorm:"not null" json:"name"`
Currency string `gorm:"not null" json:"currency"`
}
The Base looks like:
type Base struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `sql:"index" json:"deleted_at"`
}
func (base *Base) BeforeCreate(db *gorm.DB) error {
v4 := uuid.NewV4()
db.Set("ID", v4)
base.ID = v4
return nil
}
But when i tried to insert new value:
func Add(u *user.User) (account Account, err error) {
account = Account{
User: *u,
UserID: u.ID,
Currency: currency.EUR.String(),
Name: "Default",
}
err = consts.DB.Model(&Account{}).Save(&account).Error
return account, err
}
The error drops:
ERROR: insert or update on table "accounts" violates foreign key constraint "fk_accounts_user" (SQLSTATE 23503)
[9992.860ms] [rows:0] INSERT INTO "accounts" ("created_at","updated_at","deleted_at","user_id","name","currency","id") VALUES ('2023-01-30 14:55:20.261','2023-01-30 14:55:20.261',NULL,'f5e6984d-4945-4a90-9085-4d6b9d94a8c8','Default','EUR','74943fc5-d767-4e52-8044-d0e9e26e4568') RETURNING "id"
[GIN] 2023/01/30 - 14:55:21 | 400 | 4m56s | ::1 | POST "/api/v1/accounts"
In every request the reference uuid is different. On 27 of the Add function the Id and User is correct. But after saving attempt - UserID is random UUID.
The problem was in method BeforeCreate:
func (base *Base) BeforeCreate(db *gorm.DB) error {
v4 := uuid.NewV4()
db.Set("ID", v4)
base.ID = v4
return nil
}
It generated a new ID for each entity each time a record was created, and along with it, new IDs for all references
How to fix? In the Base class, add an ID field of type UUD tag default:
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid();" json:"id"`
Here gen_random_uuid() is internal PostgreSQL method available from, v14 (not sure)
So I have two structs User and Company which are as follows
//Company
type Company struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement;type:int"`
Poc_name string `json:"poc_name" gorm:"type:string;size:128;not null"`
Poc_title string `json:"poc_title" gorm:"type:string;size:255;not null"`
Poc_email string `json:"poc_email" gorm:"type:string;size:128;not null"`
Poc_phone string `json:"poc_phone" gorm:"type:string;size:128;not null"`
Default_driver_commission float32 `json:"default_driver_commission" gorm:"type:float;default:12;not null"`
Mc_number string `json:"mc_number" gorm:"type:string;size:128;default:null"`
Us_dot_number string `json:"us_dot_number" gorm:"type:string;size:128;default:null"`
Fk_user_id int `json:"fk_user_id" gorm:"not null;type:int"`
Fk_user Users `json:"user" gorm:"foreignKey:Fk_user_id"`
Time_created time.Time `json:"time_created" gorm:"autoCreateTime;not null"`
Time_updated time.Time `json:"time_updated" gorm:"autoCreateTime;not null"`
}
//User
type Users struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement;type:int"`
Username string `json:"username" gorm:"unique;not null;type:string;size:128"`
Email string `json:"email" gorm:"unique;not null;type:string;size:128"`
Password string `gorm:"not null;type:string;size:255"`
Phone string `json:"phone" gorm:"not null;type:string;size:128"`
First_name string `json:"first_name" gorm:"not null;type:string;size:128"`
Last_name string `json:"last_name" gorm:"not null;type:string;size:128"`
Provider string `json:"provider" gorm:"not null;type:string;size:128"`
Profile_picture_url string `json:"profile_picture_url" gorm:"type:text"`
Is_verified bool `json:"is_verified" gorm:"default:true;not null"`
Stripe_id string `json:"stripe_id" gorm:"not null;type:string;size:350"`
Fcm_token string `json:"fcm_token" gorm:"not null;type:string;size:350"`
Web_fcm_token string `json:"web_fcm_token" gorm:"not null;type:string;size:350"`
Hour_format_12 bool `json:"hour_format_12" gorm:"not null;default:false"`
Temp_in_centi bool `json:"temp_in_centi" gorm:"not null;default:false"`
Map_pref string `json:"map_pref" gorm:"not null;type:string;size:350"`
Time_created time.Time `json:"time_created" gorm:"autoCreateTime;not null"`
Time_updated time.Time `json:"time_updated" gorm:"autoCreateTime;not null"`
User_type int `json:"user_type" gorm:"not null"`
Address_id int `json:"address_id" gorm:"not null"`
Fk_address Address `json:"address" gorm:"foreignKey:Address_id"`
}
And this is my api call
func GetUserById(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
// var user models.Company
var user models.Users
if err != nil {
return c.Status(400).JSON("Please Ensure that :id is an integer")
}
// database.Database.Db.Preload("Fk_user.Fk_address").Where("Fk_user_id = ?", id).Find(&user)
database.Database.Db.Preload("Fk_address").Find(&user, id)
if user.Id == 0 {
return c.Status(404).JSON("User Does Not Exists")
}
// log.Fatalln(responseuser.Fk_address)
return c.Status(200).JSON(&user)
}
How can I access the company object from the user object. Previously we using Flask and SQAlchemy and it was made possible by back_ref. Is there anything similar in Gorm and Fiber ? thanks
I want to use smart select when querying rooms table. When use the original struct it works fine but when use smart select it fails.
Here is my schema
type Room struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Hash string `json:"hash" binding:"required" gorm:"not null:true"`
Users []User `json:"users" gorm:"many2many:room_users"`
Messages []Message `json:"messages"`
}
type RoomAPI struct {
ID uint `json:"id" gorm:"primary_key"`
Hash string `json:"hash" binding:"required" gorm:"not null:true"`
Users []User `json:"users" gorm:"many2many:room_users"`
//Messages []Message `json:"messages" gorm:"foreignKey:RoomID"`
}
func (RoomAPI) TableName() string {
return "rooms"
}
type User struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Name string `json:"name" binding:"required" gorm:"not null:true"`
Phone string `json:"phone"`
Email string `json:"email" binding:"required,email" gorm:"not null:true"`
Password string `json:"password" binding:"required,min=8" gorm:"not null:true"`
Gender string `json:"gender" binding:"Enum=male_female" gorm:"type:gender;not null:true;default:male"`
Rooms []Room `json:"rooms" gorm:"many2many:room_users"`
}
type Message struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Text string `json:"text" binding:"required" gorm:"not null:true"`
UserID uint `json:"user_id" gorm:"not null:true"`
RoomID uint `json:"room_id" gorm:"not null:true"`
}
here is my query
var rooms []RoomAPI
user := User{ID: userId}
err := db.DB.Model(&user).Preload("Users").
Association("Rooms").
Find(&rooms)
if err != nil {
log.Printf("err -> %+v", err)
return err, nil
}
return nil, rooms
I want to get rooms with selected fields with smart select but it fails
I have a query that fetches rows from jobs table and its author (each job has an author), but I want to select specific fields.
type User struct {
ID uint `gorm:"primarykey" json:"-"`
UUID uuid.UUID `gorm:"type:uuid not null" json:"-"`
Email string `gorm:"type:varchar(255); not null" json:"email"`
Name string `gorm:"type:varchar(255); not null" json:"name"`
AvatarURL string `gorm:"type:varchar(255); not null" json:"avatar_url"`
Provider string `gorm:"type:varchar(255); not null" json:"provider"`
ProviderID string `gorm:"type:varchar(255); not null" json:"-"`
Jobs []Job `json:"-"`
}
type Job struct {
ID uint `gorm:"primarykey" json:"id"`
Title string `gorm:"type:varchar(255); not null" json:"title"`
Content string `gorm:"not null" json:"content"`
UserID uint `json:"-"`
User User `json:"author"`
}
func (jobRepo repository) FindAll() ([]entity.Job, error) {
var jobs []entity.Job
if dbc := jobRepo.db.Preload("User", func(db *gorm.DB) *gorm.DB {
return db.Select("Name", "Email")
}).Find(&jobs); dbc.Error != nil {
return nil, dbc.Error
}
return jobs, nil
}
The custom preload does not behave as desired. If I do not specify concrete fields, the query works and returns everything. Otherwise, If I specify some fields, it returns nothing.
This is because you didn't select primary key. Add "ID" into select clause:
func(db *gorm.DB) *gorm.DB {
return db.Select("ID", "Name", "Email")
}
Otherwise GORM doesn't know how to join users to jobs.