Search code examples
gogo-gorm

Implementing a relationship with an array of values in Gorm


I'm trying to implement a model for an invoicing application using Go and Gorm. I have defined my Invoice struct and want to include the invoice line items from a separate struct.

type Invoice struct {
    Base
    CompanyID  string `gorm:"not null"`
    Company    Company
    InvoiceNo  string     `gorm:"not null"`
    Currency   string     `gorm:"not null;default:'GBP'"`
    Total      float64    `gorm:"not null"`
    Terms      int        `gorm:"not null;default:30"`
    IssuedDate time.Time  `gorm:"not null"`
    DueDate    time.Time  `gorm:"not null"`
    Paid       bool       `gorm:"not null"`
    LineItems  []LineItem `gorm:"foreignKey:InvoiceID"`
    Void       bool       `gorm:"default:false"`
}

This is my LineItem struct.

type LineItem struct {
    Base
    Service     string `gorm:"not null"`
    Description string `gorm:"not null;"`
    Amount      float64
    Count       int
    UnitBase    string  `gorm:"not null;default:'Days'"` // days or hours
    Total       float64 `gorm:"not null"`
}

When I try to build the application I get the below error.

... got error invalid field found for struct github.com/repo/API/database/models.Invoice's field LineItems: define a valid foreign key for relations or implement the Valuer/Scanner interface

The idea is that I can define a limited set up line items which can be chosen from with fixed rates and descriptions to limit repetition.

I'm unsure if I'm going about this the right/correct way.

So my question is, is it possible to include an array of items from a relational model in this way?


Solution

  • Depending on your column names, there are three ways I can think of how you can achieve this:

    1. Use default syntax (No gorm:foreignKey)

       type Invoice struct {
           ID     //this is the primary key, may also be in your base model
           Lineitems []LineItem
           ..other fields
       }
      
       type LineItem struct {
           ID          //primary key of LineItem
           InvoiceID   //automatically this will be your foreign key
           ..other fields
       }
      
    2. Specifying custom foreign key (lets say second struct has a different column name which you want as the foreignKey)

       type Invoice struct {
           ID     //this is the primary key, may also be in your base model
           Lineitems []LineItem `gorm:"foreignKey:ParentID"`
           ..other fields
       }
      
       type LineItem struct {
           ID          //primary key of LineItem
           ParentID   //this is the custom column referencing Invoice.ID
           ..other fields
       }
      
    3. Or both structs have different column names

       type Invoice struct {
           ID     //this is the primary key, may also be in your base model
           InvoiceNum 
           Lineitems []LineItem `gorm:"foreignKey:ParentNum;references:InvoiceNum"`
           ..other fields
       }
      
       type LineItem struct {
           ID          //primary key of LineItem
           ParentNum   //this is now referencing Invoice.InvoiceNum
           ..other fields
       }