I'm new to golang.
Here's my code:
//main.go
type Project struct {
gorm.Model
Name string
}
type Log struct {
gorm.Model
Project Project
User User
CheckPoint string
Status uint
}
type User struct {
gorm.Model
Name string
Password string
}
//...
db.AutoMigrate(&Project{}, &Log{}, &User{})
I want to:
Log.Project ==> Project.ID
Log.User ==> User.ID
But in the database logs table, it's:
desc logs;
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| deleted_at | datetime | YES | MUL | NULL | |
| check_point | varchar(255) | YES | | NULL | |
| status | int(10) unsigned | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
I can't see the ProjectID nor the UserID.
Any guidance?
Thank you in advance.
edit on 0825:
Hi there,
Maybe I need to explain myself firstly.
I need three tables: projects, users, logs.
In the logs, it records which user did what to which project.
I changed a little:
type Project struct {
gorm.Model
Name string
}
type User struct {
gorm.Model
Name string
Password string
}
type Log struct {
gorm.Model
ProjectID uint
UserID uint
CheckPoint string // ie: what to record
Status uint // ie: record's status
}
...
db.Debug().Model(&Log{}).AddForeignKey("user_id", "users(id)", "RESTRICT", "RESTRICT")
db.Debug().Model(&Log{}).AddForeignKey("project_id", "projects(id)", "RESTRICT", "RESTRICT")
When I ran the code,
Error 1452: Cannot add or update a child row: a foreign key constraint fails (`test`.`logs`, CONSTRAINT `logs_project_id_projects_id_foreign` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`))
Error 1452: Cannot add or update a child row: a foreign key constraint fails (`test`.`#sql-1a0f3_18`, CONSTRAINT `logs_user_id_users_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`))
I'm lost.
You are using a has one relationship so the foreign key will be in the owned models (Project & User tables should have a log_id) column. Maybe what you want is a belongs to relation.
Related
How to describe a schema for many-to-many GrhapQl relationships with custom properties?
Hi guys! I have the following tables:
+-------------+--------------+----------------------------+
| Product |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| Nutrient |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
| unit | varchar(255) | |
| alias | varchar(255) | |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| Product_To_Nutrient |
+-------------+--------------+----------------------------+
| nutrientId | int(11) | PRIMARY KEY FOREIGN KEY |
| productId | int(11) | PRIMARY KEY FOREIGN KEY |
| amount | int(11) | |
+-------------+--------------+----------------------------+
To get nutrients, I use dataloader.
How can I describe my schema so that I can run the following query and get the AMOUNT for each nutrient? Or maybe I need to rebuild my database, if so, which architecture would be optimal? Thank you in advance for your advice :)
query Product {
getProducts {
id,
name,
nutrients: {
name,
unit,
alias,
AMOUNT
}
}
My stack: TypeOrm, TypeGraphQL, MicroOrm, NodeJs.
rename the Product_To_Nutrient table to ingredients (just for convenience)
and move the unit property from the nutritient to your ingredient as it's important to know the quantity in units. (In the current situation, if you would ever have to update the unit, you also have to update all ingredients using that nutritient.
Querying with GraphQL, you'll have to do through the ingredients
query Product {
getProducts {
id,
name,
ingredients: {
nutrient: {
id,
name,
alias
},
quantity,
unit
}
}
}
To load the ingredient, when querying the products, you can make it an 'eager' relationship.
Use the Dataloader to load all the nutrients linked to the ingredient.
I am a newcomer to Go. I have an old tool to check and compare data in the Mysql database to my device, and I want to rewrite the tool in Go.
Since the tables and data have been already in the Mysql, I try to use GORM to auto map the existing tables. But I am not sure how to do that? I did not find any description of automapping an existing table in the GORM documentation.
I redeclare the existing table model and try to query data. The procedure is as below:
For example one of my tables is like this:
MariaDB [neutron]> desc lbaas_loadbalancers;
+---------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+-------+
| project_id | varchar(255) | YES | MUL | NULL | |
| id | varchar(36) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
| description | varchar(255) | YES | | NULL | |
| vip_port_id | varchar(36) | YES | MUL | NULL | |
| vip_subnet_id | varchar(36) | NO | | NULL | |
| vip_address | varchar(36) | YES | | NULL | |
| admin_state_up | tinyint(1) | NO | | NULL | |
| provisioning_status | varchar(16) | NO | | NULL | |
| operating_status | varchar(16) | NO | | NULL | |
| flavor_id | varchar(36) | YES | MUL | NULL | |
+---------------------+--------------+------+-----+---------+-------+
11 rows in set (0.002 sec)
MariaDB [neutron]> select * from lbaas_loadbalancers \G;
*************************** 1. row ***************************
project_id: 346052548d924ee095b3c2a4f05244ac
id: f6638d02-29f8-41aa-9433-179bf49f5fbd
name: test1
description:
vip_port_id: 21cebbd5-fa4c-4d20-9858-d14ba3eacea8
vip_subnet_id: 0916f471-afcd-48ee-afc5-56bcb0efa963
vip_address: 172.168.1.6
admin_state_up: 1
provisioning_status: ACTIVE
operating_status: ONLINE
flavor_id: NULL
1 row in set (0.003 sec)
Then I try to use GORM mapping the table. I just chosen two fields ID and Name for the test.
package main
import (
"log"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// declare only two attribute in the model for test purpose
type Lbaas_loadbalancers struct {
ID string
Name string
}
func main() {
var lb Lbaas_loadbalancers
dsn := "test:test#tcp(192.168.0.17:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("connection error")
}
test := db.Take(&lb)
log.Println("test err is ", test.Error)
log.Println(test.RowsAffected)
// this line report error: ./db.go:25:6: test.ID undefined (type *gorm.DB has no field or method ID)
log.Println(test.ID)
// if I comment the above line, this print out 'mysql', but the actual name is 'test1'.
log.Println(test.Name())
}
Finally, I run go run db.go, I got this error:
➜ test git:(main) ✗ go run db.go
# command-line-arguments
./db.go:27:20: cannot convert test.Config.Dialector.Name (type func() string) to type string
It seems not the right way to do it. what is the correct way to auto map an existing database in Mysql by using GORM module?
If the below code is the correct way, why I cannot get the ID attribute from the return value of db.Take method directly? Do I need to do data conversion?
Please give me some hints, thanks.
I know what is wrong here, I should not get ID and Name from the db.Take return, It takes the address of lb variable, and change the lb.
I am so silly, just realized the problem. :)
I have the following 2 gorm models
// Day is a corresponding day entry
type Day struct {
gorm.Model
Dateday string `json:"dateday" gorm:"type:date;NOT NULL"`
Nameday string `json:"nameday" gorm:"type:varchar(100);NOT NULL"`
Something sql.NullString `json:"something"`
Holyday bool `json:"holyday"`
}
type Week struct {
gorm.Model
Start Day
End Day
}
However, after performing the migrations
db.AutoMigrate(&Day{})
db.AutoMigrate(&Week{})
logging into the db and describing table weeks
postgres-# \d+ weeks;
Table "public.weeks"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
------------+--------------------------+-----------+----------+-----------------------------------+---------+--------------+-------------
id | integer | | not null | nextval('weeks_id_seq'::regclass) | plain | |
created_at | timestamp with time zone | | | | plain | |
updated_at | timestamp with time zone | | | | plain | |
deleted_at | timestamp with time zone | | | | plain | |
Indexes:
"weeks_pkey" PRIMARY KEY, btree (id)
"idx_weeks_deleted_at" btree (deleted_at)
I don't see the start / end fields, that should presumably also be Foreign Key to the day table (that does exist)
Why is that?
To set one-to-one relationship you need to also add id field to struct. By default you should name it as [YourFieldName]ID, if you want to use some other name for id field, you can do it via tag (see docs for more details), for example:
type Week struct {
gorm.Model
Start Day
End Day `gorm:"foreignkey:EndRefer"`
StartID uint
EndRefer uint
}
But beware, AutoMigrate can't create foreign key constraint(here's related issue). You have to set it yourself with AddForeignKey method.
Let's say I have a parent and a child table, in Laravel, for table Order, my model would look like this:
public function up()
{
Schema::create('orders', function(Blueprint $table)
{
$table->integer('customer_id')->unsigned();
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');
$table->increments('id');
I know Eloquent would consider id to be the primary key of orders, so an index would be automatically created on that primary key.
What should I do to make sure that customer_id is part of the primary key's index, setup in that order:
1. customer_id
2. id
Example of tables
Customer
+-------------+
| id | --> primary key
|- - - - - - -|
| name |
| address |
+-------------+
|
|
|
A
Order
+------------------+
| customer_id (fk) | --- primary key
| id | --- primary key
|- - - - - - - - - |
| date |
+------------------+
Will Eloquent automatically add this foreign key to the primary key's index?
Well, not automatic but its very easy.
To specify custom primary key, you can call primary() method from Blueprint class, called through $table. ie $table->primary().
For a single primary key, it accepts a string specifying the name of column to be made primary.
For composite key, you can pass an array of strings of the columns to be made primary. In your case
$table->primary(
['id', 'customer_id']
)
I decided to try this out and see what happens.
Starting with the customers table, I ran this statement...
CREATE TABLE customers (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
created_at DATETIME,
updated_at DATETIME,
PRIMARY KEY (id)
);
I then created the following...
CREATE TABLE orders (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
customer_id INT(11) UNSIGNED,
created_at DATETIME,
updated_at DATETIME,
PRIMARY KEY (id, customer_id)
);
Note here if you use PRIMARY KEY (customer_id, id), it will result in a SQL error. This makes me believe the DB2 functionality you are trying to replicate will not work exactly the same on MySQL and we actually need a foreign key.
Then after filling these tables with test data, I ran the following...
EXPLAIN SELECT *
FROM customers
INNER JOIN orders ON customers.id = orders.customer_id;
This results in
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------------------------------------------+
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | ref | ROWS | Extra |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------------------------------------------+
| 1 | SIMPLE | customers | ALL | PRIMARY | NULL | NULL | NULL | 4 | |
| 1 | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | 262402 | USING WHERE; USING JOIN buffer (flat, BNL JOIN) |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------------------------------------------+
I then added the foreign key...
ALTER TABLE orders ADD FOREIGN KEY customer_id (customer_id) REFERENCES customers (id) ON DELETE CASCADE ON UPDATE CASCADE;
And running the same exact explain query before with the same exact data, I now get the results...
+------+-------------+-----------+------+---------------+-------------+---------+-----------------------+-------+-------+
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | ref | ROWS | Extra |
+------+-------------+-----------+------+---------------+-------------+---------+-----------------------+-------+-------+
| 1 | SIMPLE | customers | ALL | PRIMARY | NULL | NULL | NULL | 4 | |
| 1 | SIMPLE | orders | ref | customer_id | customer_id | 4 | cookbook.customers.id | 43751 | |
+------+-------------+-----------+------+---------------+-------------+---------+-----------------------+-------+-------+
As you can see, much fewer rows are being evaluated when I add the foreign key which is exactly what we are looking for. Surprising for me probably because I'm not a DBA, running the following produces the same results...
EXPLAIN SELECT * FROM orders WHERE customer_id = 4;
Even in this case, the composite primary key isn't doing anything for you however the foreign key is helping immensely.
With all that said, I think it's safe to forego the composite primary key and just set the id up as primary and set the customer_id up as a foreign key. This also gives you the benefit of being able to cascade deletes and updates.
User Model
| Field | Type
+-----------------+-----------------
id | int(10) unsigned | NO
name | varchar(255) | NO
email | varchar(255) | NO
Club Model
Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+-------------------+-------+
| id | int(10) unsigned | NO | | NULL | |
| user_id | int(10) unsigned | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
Club member Model
+------------+------------------+------
Field | Type
id | int(11)
club_id | int(10)
user_id | int(10)
status | varchar(20)
How to make relationship using laravel?
I assume that User has many club .
in User Model
`public function clubs()
{
return $this->hasMany('App\Club');
}`
Club has many members(users). I created ClubMember model
how to declare the relation in clubMember model? and **club member belongs to club and user **
Looks like a many to many relationship to me. Your "Club member Model" table is the pivot table.
You can add this relation to your user model:
public function clubs()
{
return $this->belongsToMany('App\Club', 'PIVOT TABLE NAME');
}
and this to your club model:
public function users()
{
return $this->belongsToMany('App\User', 'PIVOT TABLE NAME');
}
Change PIVOT TABLE NAME to the name of your table. Laravel assumes that it is named "club_user". If you name it like this, you dont need to add the second parameter.
Check the Laravel documentation for more information on many to many relationships.