1

for some reason my GORM is trying to save a nil relation to the database as a zero struct and is then running into foreign key errors, because the foreign key ID is 0 (does not exist).

I have the following model definitions:

type Member struct {
    gorm.Model

    EmployerID *uint    `json:"employer_id,omitempty"`
    Employer   Employer `json:"employer"`
}

type Employer struct {
  gorm.Model

  CompanyID uint     `json:"company_id"`
  Company   *Company `json:"company"`

  ExternalPayrollCompanyID *uint    `json:"external_payroll_company_id,omitempty"`
  ExternalPayrollCompany   *Company `json:"external_payroll_company,omitempty"`
}


type Company struct {
    gorm.Model

    AddressID        uint          `json:"address_id,omitempty"`
    Address          *Address      `json:"address,omitempty"`
}

type Address struct {
    gorm.Model

    StreetNr string `gorm:"type:varchar(600);not null" json:"street_nr,omitempty"`
    ZipCode  uint   `gorm:"type:int;not null" json:"zip_code,omitempty"`
    City     string `gorm:"type:varchar(600);not null" json:"city,omitempty"`
}

As you can see, an Employer always has a Company, and possibly an ExternalPayrollCompany. If a Company exists, it always has an Address.

I have a unit test, in which an Employer has a set Company, but a nil ExternalPayrollCompany. When I Create it in the database, GORM acts as expected (the ExternalPayrollCompany-ID is NULL, and no "empty" Company is created):

employer := Employer{
    Company: &Company{
        Name: "123",
        Address: &Address{
            StreetNr: "Asdf 13",
            ZipCode:  69999,
            City:     "Asdf",
        },
    },
}
db.Create(employer)

However, when the Employer is nested in a parent Member model:

member := Member{
    Employer: Employer{
        Company: &Company{
            Name: "123",
            Address: &Address{
                StreetNr: "Asdf 13",
                ZipCode:  69999,
                City:     "Asdf",
            },
        },
    },
}
db.Create(member)

then the nil value for ExternalPayrollCompany is ignored, an empty Company with an AddressID of 0 is inserted, and the DB engine complains about a foreign key error, since no Address with ID 0 exists.

It would also appear that GORM is initializing the ExternalPayrollCompany and then setting the timestamps, as the following is output in the debug mode:

INSERT INTO [companies] ([created_at],[updated_at],[name],[address_id]) OUTPUT Inserted.[id] VALUES ('2020-05-10 15:46:05','2020-05-10 15:46:05','',0)

I disabled the timestamp callback to no effect:

db.Callback().Create().Remove("gorm:update_time_stamp")

I would appreciate any input, since I am running out of ideas!

BN-WSW
  • 11
  • 4

1 Answers1

0

Alright, in case someone else is landing on here and you are using Postgres:

I had this same issue and for me it happened because I had inserted other records previously and passed an ID explicitly. If you do this, Postgres will not update the sequential IDs and will attempt to create an ID where it left off. You'll notice that if you keep trying the same insert, it will eventually work as Postgres keeps calling next_val on your erroneous queries until it hits an ID that is not taken.

See this question for more info. Hope that helps some other poor soul.

vanamerongen
  • 837
  • 3
  • 11
  • 27