Golang's GORM not adding associations to "has many" relationship - go

I just started using GORM and tried to build a "has many relationship". I'm trying to add an association to Previous.Holdings (I think I followed the docs correctly) but when I try to do a select * from previous I don't see anything showing up in the database. Any idea on what I'm missing.
import (
orm "github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
type Previous struct {
orm.Model
Holdings []Holding `gorm:"foreignkey:ID"`
}
type Holding struct {
ID uint `gorm:"primary_key"`
Symbol string
PurchaseDate time.Time
SellDate time.Time
}
func main() {
t1, _ := time.Parse("2006-01-02", "2017-06-16")
h := Holding{
Symbol: "abc",
PurchaseDate: t1,
}
db.Model(&Previous{}).Association("Holdings").Append(h)
}

First of all you should create your previous table. You can make that by making migrations. You probably should make that migrations after db connection initialization. e.g.
db.AutoMigrate(&Previous{})
So when u using db.Model(&Previous{}) you not saving any entity and if u wanna make asscociation with Holdings entity you need as first step to Save or Find existing Previous record by doing e.g.
previous := &Previous{}
db.Save(previous)
After that you can append your holding record to Model like you do in your code but changing referenced Previous. So it will look like this
h := Holding{
Symbol: "abc",
PurchaseDate: t1,
}
db.Model(previous).Association("Holdings").Append(h)
I don't know if its for testing but when you modeling entities you can make referenced id whithout specifing foreign key also you are using your Holding ID as ForeignKey so ID of Previous will be your ID of Holding.
For me your model declaration should look like this (PreviousID will be automaticaly signed as foreign key for Previous)
type Previous struct {
orm.Model
Holdings []Holding
}
type Holding struct {
ID uint `gorm:"primary_key"`
PreviousID uint
Symbol string
PurchaseDate time.Time
SellDate time.Time
}

Related

GoLang GORM Cyclical Binary Tree

I'm trying to model a database in GoLang (go 1.16) using GORM (gorm.io/gorm v1.21.9).
Part of my schema includes table A with 2 optional foreign keys, in practice only 1 will be used for each record. Table B contains 2 references to table A, like a binary tree. Table C is a leaf node.
Figure 1. Entity Relationship Diagram
Figure 2. Example Usage
I have the GORM code set up as shown below.
type A struct {
ID string
BID *string
B *B
CID *string
C *C
}
type B struct {
ID string
LeftAID string
LeftA A
RightAID string
RightA A
}
type C struct {
ID string
}
When I load the application with sample data, table B always has null values for it's foreign keys.
However, Table A has a value for table_b_id for every record (should be null when table_c_id exists).
I'm guessing that, since table A has a foreign key to table B, it's using that association in all cases, instead of picking up the right_a_id and left_a_id associations. Is there a GORM annotation that will fix this, or is this a limitation inherent to GORM?
Please note that I have removed the unrelated schema information and used abstracted table/column names.
Maybe you should uses
Self-Referential Has One
Self-Referential Has One
like follow
type A struct {
ID string
LeftID *string
LeftA *A `gorm:"foreignkey:LeftID"`
RightID *string
RightA *A `gorm:"foreignkey:RightID"`
LeafID *string
LeafA *A `gorm:"foreignkey:LeafID"`
}
test code:
func main() {
db := config.CreateMysql()
db.AutoMigrate(&A{})
a1 := A{ID: "a1"}
a2 := A{ID: "a2"}
a3 := A{ID: "a3"}
a4 := A{ID: "a4"}
a5 := A{ID: "a5"}
a1.LeftA = &a2
a1.RightA = &a3
a4.LeafA = &a5
db.Create(&a1)
db.Create(&a4)
}
in db like this:

How to fetch last record in gorm?

I'm working on a golang application in which I need to fetch last record from the table so I'm not able to do it. I have models mention below:-
type SQLTransaction struct {
Id int `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty" gorm:"primaryKey"`
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"`
VmStatusId int `protobuf:"bytes,6,opt,name=vm_status_id,proto3" json:"vm_status_id,omitempty"`
}
Here is my gorm function in which I want to fetch the last record
func (mgr *manager) GetLastTxn() (int, error) {
var versionId int
resp := mgr.connection.Table("transactions").Last("", "version")
return versionId, resp.Error
}
Error:-
model value required
[0.053ms] [rows:0] SELECT * FROM `transactions` WHERE version ORDER BY `transactions`. DESC LIMIT 1
0 model value required
How can I achieve it please any help. Thanks in advance.
There are a couple of issues in your example that should be handled.
First, the error model value required suggests that the Last method needs a model to store the result. If you want the entire record with all the data you can do it like this:
var lastVersion SQLTransaction
resp := mgr.connection.Table("transactions").Last(&lastVersion)
If you only want the ID of the record, you do something like this:
var lastVersion struct {
ID int
}
resp := mgr.connection.Table("transactions").Last(&lastVersion)
Next, you don't need Last("", "version") because it doesn't do what you think it does. The first parameter is a pointer to your resulting object (which for all go-gorm methods always should be an object or a slice). The second one is a condition for the WHERE clause. So the correct syntax, if you don't need an additional WHERE clause, is:
resp := mgr.connection.Table("transactions").Last(&lastVersion)
If you look at the code of the Last method, it considers the primary key when it executes the method, so you don't even need any additional parameters or conditions.

db.First() not using primary key name

I am writing some sample code to understand gorm but appear to be having an issue with setting up the primary_key value. As a result, the resulting SQL query is broken.
Please see the sample code:
package main
import (
"os"
"fmt"
"time"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Post struct {
id int `json:"id" gorm:"primary_key:id"`
url string `gorm:"url"`
content string `gorm:"content"`
created_at time.Time `gorm:"created_at"`
normalized string `gorm:"normalized"`
account_id int `gorm:"account_id"`
posthash []byte `gorm:"posthash"`
received_at time.Time `gorm:"received_at"`
}
func main() {
dsn := "user=postgres dbname=localtest"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("An error occurred", err)
os.Exit(1)
}
db.AutoMigrate(&Post{})
var post Post
db.First(&post, 1)
fmt.Println(post)
}
When I run this code, I receive the following error:
$ go run gorm_test.go
2020/12/01 00:34:06 /home/farhan/gorm_test.go:32 ERROR: syntax error at or near "=" (SQLSTATE 42601)
[0.128ms] [rows:0] SELECT * FROM "posts" WHERE "posts". = 1 ORDER BY "posts". LIMIT 1
{0 {0 0 <nil>} 0 [] {0 0 <nil>}}
The nature of this error suggests to me that the primary_key value is not set. I tried primaryKey and primarykey, but none appeared to work. Any ideas?
#Shubham Srivastava - Your structure declaration is bad; you need to export fields so gorm can use them Declaring Models
❗️Use exported ID field
In Go, when a field name starts with a lowercase letter that means the field is private (called unexported in Go parlance). Gorm, being a third party package, cannot see inside your struct to know there is an id field, or any other unexported field for that matter.
The solution is to make sure all the fields that need to come from the DB are exported:
type Post struct {
ID uint `json:"id" gorm:"primaryKey"`
...
}

Grandchild foreign key

I'm creating a rest application in Go, and am using GORM for my orm. So far I successfully have everything implemented however I'm now wanting to add some further details to my model in order to make the front end application easier.
This will be adding "grandchildren" foreign keys (Can't think of a better thing to call it). I can't see anything in the documentation about this but effectivly what i'm wanting is the following:
type Map struct{
Id int `gorm:"primaryKey"`
Buildings []Building `gorm:"references:Id"`
}
type Building struct{
Id int `gorm:"primaryKey"`
MapId int
Floors []Floor `gorm:"references:Id"`
}
type Floor struct{
Id int `gorm:"primaryKey"`
BuildingId int
MapId int
}
To clarify, I'm unsure how to get the map ID into the database for the Floor struct and from reading documentation I can't seem to find a way of doing this, if anyone can link to some documentation or an example that would be great, please note: I don't want to hold an instance of the map within the floor just the ID.
Answer for people finding this in the future:
After posting on GORM git page (https://github.com/go-gorm/gorm/issues/3788) i was directed towards hooks: https://gorm.io/docs/hooks.html#Hooks
My code to solve this is to use a before create for each sub level wgere u then set the approriate values iterativly over the list of sub structs like so:
func (building *Building) BeforeCreate(tx *gorm.DB) (err error){
for i := 0; i < len(building.Floors); i++ {
building.Floors[i].MapId = building.MapId
}
return
}

Using sqlx, to populated embedded structs from a table joined twice

My question in a nutshell: can I use sqlx's StructScan to populate two embedded structs with values sourced from the same SQL table joined twice?
The help files to the useful sqlx package state this:
A StructScan will set an id column result in Person.AutoIncr.ID, also accessible as Person.ID. To avoid confusion, it's suggested that you use AS to create column aliases in your SQL instead.
Supposed I have this SQL query (parent-child, people to phones):
func getSQL() string {
return `SELECT *
FROM person
LEFT JOIN phones AS Phone1 ON Phone1.phone_id = person_phoneID1
LEFT JOIN phones AS Phone2 ON Phone2.phone_id = person_phoneID2
WHERE people_id = 1;`
}
Using sqlx and StructScan, I'd like to populate a struct full of embedded structs, something like this:
//Struct with embedded structs
type personHelper struct{
Person
Phone1 //Should I use the same name as SQL table alias?
Phone2
}
type Phone1 struct {
Phone //Underlying struct
}
type Phone2 struct{
Phone
}
//Base structs, with tags to match up fields
type Person struct{
ID `db:"person_id"`
Name `db:"person_name"`
Phone1 `db:"person_phoneID1"`
Phone2 `db:"person_phoneID2"`
}
type Phone struct{
ID int64 `db:"phone_id"`
Number string `db:"phone_no"`
//etc.
}
I might have a function something like this:
func getPeople(){
parseRows := func(rows *sqlx.Rows) {
for rows.Next() {
var ph personHelper
err := rows.StructScan(&ph)
if err != nil{
//etc.
}
}
}
sql := getSQL()
sqlutils.GetRows(parseRows, sql)//GetRows executes the SQL query and returns rows for processing
}
I can populate one phone number, but not both. I'm not sure whether I'm understanding the aliasing instructions correctly.
I'd appreciate any insights.
Thanks.

Resources