Gorm relationship error: need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface

Viewed 12612

I am troubleshooting an issue that just came up while using Gorm. I had everything working great with my sqlite3 database and Go data models, but then when I had some issues with dependencies not 'go get'ing in the build environment, so I tried copying/deleting some packages from the vendor folder, re 'go get'ing until I got the build working... But now when I compile and run in my own machine, Im getting issues I never had before.

When I attempt something like this (configID is already checked to ensure it has a valid entry):

    var config models.ConfigurationDescription

    // Find the Configuration
    results := db.Where("id = ?", configID).
        Preload("Location").
        Find(&config)

Gorm is throwing the following error:

 "invalid field found for struct `models.ConfigurationDescription`'s field Location, need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface"

This is how I have defined the data models (which were working great prior to the dependency jumble):

package models

type LocationDescription struct {
    ID       int    `json:"locationID"`
    Name     string `json:"name"`
    IsActive bool   `json:"isActive"`
}

func (LocationDescription) TableName() string { return "locations" }

type ConfigurationDescription struct {
    ID         int                 `json:"configurationID"`
    Name       string              `json:"name"`
    IsActive   bool                `json:"isActive"`
    LocationID int                 `json:"-"`
    Location   LocationDescription `json:"location,omitempty" gorm:"foreignKey:ID;references:LocationID"`
}

func (ConfigurationDescription) TableName() string { return "configurations" }

Thats being run against a sqlite database with this setup:

CREATE TABLE IF NOT EXISTS locations (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    name         TEXT,
    latitude     REAL CHECK (latitude > 0),
    longitude    REAL CHECK (latitude > 0),
    is_active    INTEGER DEFAULT 0
);

CREATE TABLE IF NOT EXISTS configurations (
    id               INTEGER PRIMARY KEY AUTOINCREMENT,
    location_id      INTEGER,
    name             TEXT,
    is_active        INTEGER DEFAULT 0,
    CONSTRAINT location_fk FOREIGN KEY (location_id) REFERENCES locations(id) ON DELETE CASCADE
);

I know it was working and I didn't change any of the code. And everything Im seeing looks like it follows the docs to the T, so it doesn't make sense that it would be like an update to the dependency broke something, because it doesn't appear that there has been any breaking changes.....

AND! The real kicker is that this works:

var location models.Location
DB.Where("is_active = ?", true).
        Preload("Configurations").
        Find(&location)

(these structs and the database actually have many more fields, but for simplicity, Ive trimmed them down)

type Location struct {
    ID             int             `json:"locationID"`
    Name           string          `json:"name"`
    Latitude       null.Float      `json:"latitude,omitempty"`
    Longitude      null.Float      `json:"longitude,omitempty"`
    IsActive       null.Bool       `json:"isActive" gorm:"default:false"`
    Configurations []Configuration `json:"configurations,omitempty" gorm:"foreignKey:LocationID;references:ID"`
}

type Configuration struct {
    ID             int             `json:"configurationID"`
    LocationID     int             `json:"locationID"`
    Name           string          `json:"name"`
    IsActive       null.Bool       `json:"isActive" gorm:"default:false"`
}

So the question is, does anyone know what might be causing this? And more importantly, have any suggestions for how to fix the issue?

1 Answers

It seems to me that you've got your tags the wrong way around for the LocationDescription field.

First, this is a Belongs-To relationship pattern.

  • foreignKey should name the model-local key field that joins to the foreign entity.
  • references should name the foreign entity's primary or unique key.

Try with:

type ConfigurationDescription struct {
    ID         int                 `json:"configurationID"`
    Name       string              `json:"name"`
    IsActive   bool                `json:"isActive"`
    LocationID int                 `json:"-"`
    Location   LocationDescription `json:"location,omitempty" gorm:"foreignKey:LocationID;references:ID"`
}
Related