Gorm: Many-to-Many and attributes

Created on 10 Nov 2015  路  3Comments  路  Source: go-gorm/gorm

Hi !

I was wondering what would be the best way to create a many-to-many relationship with extra attributes ? For instance, I'd like to have Library <--> LibraryHasBook (count) <--> Books. LibraryHasBook would have the following fields (library_id, book_id, count). Has anyone done or seen that pattern before ?

I was thinking of:

type Library struct {
    ID            uint   `gorm:"primary_key"`
    Name      string
    Books     []LibraryHasBook
}

type LibraryHasBook struct {
    Library   Library   `gorm:"primary_key"`
    Book Book `gorm:"primary_key"`
    Count   uint
}

type Book struct {
    ID            uint   `gorm:"primary_key"`
    Name      string
    Libraries  []LibraryHasBook
}

And then inserting a new Book & associated Libraries with something like:

book := Book{
    Name: "The Lords of the Ring",
    Libraries: []LibraryHasBook {
        LibraryHasBook{
            Library: Library{Name: "Tolkien Specialists"},
            Count: 10,
        },
        LibraryHasBook{
            Library: Library{Name: "Awesome Library"},
            Count: 3,
        },
    },
}
db.Create(&book)

But I am quite not sure if it would work (the Go is most likely not valid anyways as I typed it directly in that issue), especially if GORM would be able to fill LibraryHasBook's Library, and what annotation should be used, etc. Should I instead use a transaction, create Libraries, create Book, then LibraryHasBooks, specifying explictely the book/librairies and commit, would it work better ?

How would it be possible then to get a book with its Libraries and count ?

I did not find anything related in the docs, pardon me if I am blind.
Thank you so much.

Most helpful comment

Hi @Quentin-M

yes, it is possible to do this, refer below example

package main

import (
    "github.com/davecgh/go-spew/spew"
    _ "github.com/lib/pq"

    "github.com/jinzhu/gorm"
)

type User struct {
    ID         int
    Email      string
    GroupUsers []*GroupUser
}

type Group struct {
    ID         int
    Name       string
    GroupUsers []*GroupUser
}

type GroupUser struct {
    ID      int
    Group   *Group
    GroupID int
    User    *User
    UserID  int
    Owner   bool
}

func (*GroupUser) TableName() string {
    return "group_user"
}

func main() {
    db, err := gorm.Open("postgres", "user=gorm DB.name=gorm sslmode=disable")
    if err != nil {
        panic(err)
    }
    db.AutoMigrate(&User{}, &Group{}, &GroupUser{})

    db.LogMode(true)

    db.Debug().Save(&User{
        Email: "[email protected]",
        GroupUsers: []*GroupUser{
            {
                Group: &Group{
                    Name: "ccc",
                },
                Owner: true,
            },
        },
    })

    var group Group
    if err := db.Preload("GroupUsers.User").First(&group).Error; err != nil {
        panic(err)
    }

    spew.Dump(group)
}

All 3 comments

Hi @Quentin-M

yes, it is possible to do this, refer below example

package main

import (
    "github.com/davecgh/go-spew/spew"
    _ "github.com/lib/pq"

    "github.com/jinzhu/gorm"
)

type User struct {
    ID         int
    Email      string
    GroupUsers []*GroupUser
}

type Group struct {
    ID         int
    Name       string
    GroupUsers []*GroupUser
}

type GroupUser struct {
    ID      int
    Group   *Group
    GroupID int
    User    *User
    UserID  int
    Owner   bool
}

func (*GroupUser) TableName() string {
    return "group_user"
}

func main() {
    db, err := gorm.Open("postgres", "user=gorm DB.name=gorm sslmode=disable")
    if err != nil {
        panic(err)
    }
    db.AutoMigrate(&User{}, &Group{}, &GroupUser{})

    db.LogMode(true)

    db.Debug().Save(&User{
        Email: "[email protected]",
        GroupUsers: []*GroupUser{
            {
                Group: &Group{
                    Name: "ccc",
                },
                Owner: true,
            },
        },
    })

    var group Group
    if err := db.Preload("GroupUsers.User").First(&group).Error; err != nil {
        panic(err)
    }

    spew.Dump(group)
}

@jinzhu How do I append and delete items in such relationships?

@rbatukaev User, GroupUser are normal has many relations, refer https://github.com/jinzhu/gorm#association-mode

Was this page helpful?
0 / 5 - 0 ratings

Related issues

koalacxr picture koalacxr  路  3Comments

easonlin404 picture easonlin404  路  3Comments

fieryorc picture fieryorc  路  3Comments

leebrooks0 picture leebrooks0  路  3Comments

bramp picture bramp  路  3Comments