I have the following models:
type User struct {
ID int64 `orm:"pk;auto;column(id)" json:"id"`
FirstName *string `json:"first_name"`
LastName *string `json:"last_name" orm:"null"`
FullName *string `json:"full_name"`
Posts []*Post `orm:"rel(m2m);rel_through(demo/db/models.UserPosts)" json:"posts"`
}
and
type UserPosts struct {
ID int64 `orm:"pk;auto;column(id)" json:"id"`
Post *Post `orm:"rel(fk);column(post_id)" json:"post"`
User *User `orm:"rel(fk);column(users_id)" json:"user"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
IsInactive bool `json:"is_inactive"`
}
and
type Post struct {
ID int64 `orm:"pk;auto;column(id)" json:"id"`
Content *string `json:"content"`
Type *string `json:"type" orm:"null"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
IsInactive bool `json:"is_inactive"`
Users []*User `orm:"reverse(many)" json:"users"`
}
I want to order the distinct users queried via the created_at field of the Post table.
But whenever I run the following query
import "github.com/astaxie/beego/orm"
db := orm.NewOrm()
qs := db.QueryTable(new(models.User))
num, err := qs.Distinct().RelatedSel().All(&users)
The query formed by beego does not contain the field created_at of Post table and hence it gives an error. The query for the same is listed below:
SELECT DISTINCT T0."id", T0."first_name", T0."last_name", T0."full_name"
FROM "users" T0
INNER JOIN "user_posts" T1
ON T1."users_id" = T0."id"
WHERE T1."tenants_id"
IN $1
AND T1."is_inactive" = $2
ORDER BY T1."created_at" DESC ;
I checked through the documentation but wasn't able to find any hint to the solution.
NOTE: The disctinct is required due to other constraints I have in my code which I have not highlighted in the question since that is out of scope
Hoping someone can point me in the right direction to achieve the same.
Related
I keep getting error Technician: unsupported relations for schema Ticket for this struct schema and query? What can I do to get make this Preload query works?
Or at least how can debug this issue? The error is pretty bare minimal and I have read the gorm preload page https://gorm.io/docs/preload.html, and don't get what I did wrong?
type Ticket struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ShopID uuid.UUID `json:"shopID"`
Archived bool `json:"archived"`
Services []string `json:"services"`
Price int `json:"price"`
Location int `json:"location"`
Checkedout bool `json:"checkedout"`
TechnicianID uuid.UUID `json:"technicianId"`
Technician Technician `json:"technician"`
TechnicianPartnerID *uuid.UUID `json:"technicianPartnerId"`
LastUpdatedBy uuid.UUID `json:"lastupdatedBy"`
}
type Technician struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ShopID uuid.UUID `json:"shopID"`
Name string `json:"name"`
Active bool `json:"active"`
}
dbQuery := t.Db.Orm.WithContext(ctx).Table("tickets").Preload("Technician")
You are not using the standard gorm.Model for the keys (from the docs):
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
Gorm uses this to identify joins.
Changing your keys with the gorm:"primaryKey" indicator should fix the issue.
Or alternative: use gorm.Model:
type Ticker struct {
gorm.Model
ShopID uuid.UUID `json:"shopID"`
Archived bool `json:"archived"`
Services []string `json:"services"`
Price int `json:"price"`
Location int `json:"location"`
Checkedout bool `json:"checkedout"`
TechnicianID uuid.UUID `json:"technicianId"`
Technician Technician `json:"technician"`
TechnicianPartnerID *uuid.UUID `json:"technicianPartnerId"`
LastUpdatedBy uuid.UUID `json:"lastupdatedBy"`
}
type Technician struct {
gorm.Model
ShopID uuid.UUID `json:"shopID"`
Name string `json:"name"`
Active bool `json:"active"`
}
I am playing with gin-gonic+sqlx. Now I wonder what is the best way to dynamically bind database records to the struct?
Saying I have a struct and a query like this.
type Project struct {
ID string `db:"id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
DeletedAt NullTime `db:"deleted_at"`
Name string
Status string
OpenDate NullTime `db:"open_date"`
Number uint
}
func (p Project) List() ([]Project, error) {
var pp []Project
err := db.Select(&pp, "SELECT * FROM Project")
return pp, err
}
Now I want to add field-level permissions to this struct. For example, an admin can view and edit all fields; User A can view CreatedAt and Name; User B can view and edit Name Status and view Number.
I was writing multiply structs for each use case, but obviously, I did choose the silliest way.
The other method I can think of is to implement Struct Tag. Am I on the right track or is there a better way to do this?
We can create multiple structs and embed among each other.
Example:
type ProjectSummary struct {
ID string `db:"id"`
Name string
}
type ProjectUser struct {
ProjectSummary
CreatedAt time.Time `db:"created_at"`
}
type ProjectSupport struct {
ProjectSummary
Status string
Number uint
}
type ProjectAdmin struct {
ProjectSupport
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
DeletedAt NullTime `db:"deleted_at"`
OpenDate NullTime `db:"open_date"`
}
I have a problem with foreign key selection with gorm on MySQL database.
I got a file dto.go:
package dto
import (
"time"
)
type TaskResponse struct {
ID uint `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Status model.Status
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
A simple response object, but a task have a Status param.
I got a file task.go and status.go:
package model
// Status struct
type Status struct {
ID uint
Name string
}
// Task struct
type Task struct {
gorm.Model
ID uint
Title string
Description string
Status Status `gorm:"ForeignKey:ID"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
The request:
database.DB.Model(&model.Task{}).First(dest, conds...)
The problem is that I would like to add in TaskResponse the result of request, but all the task fields are retrieved but the Status object is always empty ... (I try many things like the actual gorm:"ForeignKey:ID")
Someone know what is my problem?
I have a many2many relation between news and tag. Whenever I tried to assign news to a tag it gives me an error Error 1062: Duplicate entry '5' for key 'news_id'
My model look like this:
type Tag struct {
ID uint64 `json:"id" gorm:"primary_key;unique;AUTO_INCREMENT"`
Title string `json:"title" gorm:"varchar(20)" binding:"required"`
News []*News `json:"news" gorm:"many2many:news_tags;association_foreignkey:ID;foreignkey:ID"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
// News model
type News struct {
ID uint64 `json:"id" gorm:"primary_key;unique;AUTO_INCREMENT"`
Title string `json:"title" gorm:"varchar(20)" binding:"required"`
Body string `json:"body" gorm:"varchar(500)" binding:"required"`
Status string `json:"status" gorm:"varchar(5)"` // 1 = publish; 2 = draft; 3 = deleted;
Tags []*Tag `json:"tags" gorm:"many2many:news_tags;association_foreignkey:ID;foreignkey:ID"`
Topics []*Topic `json:"topics" gorm:"many2many:news_topics"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
// My code when trying to assign new tag
func (n *News) AssignTags(tag Tag) {
db.DB().Model(n).Association("Tags").Append(tag)
}
I have a Room search, which requires the Room struct to contain the entire User struct.
type Room struct {
ID *int64 `json:"id"`
CreatedAt *time.Time `json:"created_at,omitempty" gorm:"not null"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
User *User `json:"user,omitempty"`
UserID *int64 `json:"user_id,omitempty"`
}
and
type User struct {
ID *int64 `json:"id"`
CreatedAt *time.Time `json:"created_at,omitempty" gorm:"not null"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
FirstName *string `json:"first_name,omitempty"`
LastName *string `json:"last_name,omitempty"`
}
while the search function looks like this
func searchRoom(db *gorm.DB, q string) ([]Room, error) {
q = "%" + q + "%"
rooms := []Room{}
db.Preload("User").
Joins("LEFT JOIN users on rooms.user_id = users.id").
Where(
"CONCAT(users.first_name, ' ', users.last_name) LIKE ?",
q,
).
Find(&rooms)
return rooms, nil
}
This works pretty well the way it is expected, however, to me this looks a bit clunky, I went through Gorm docs, but didn't find anything else which could help me.
I could use the db.Raw method, but that does not fill the user struct automatically.
Is there a better way to use Gorm and make it more performant?