Get nested object in structure in gorm

2019-07-14 06:04发布

问题:

I have a two structure:

type GoogleAccount struct {
     Id     uint64
     Token  string
}

It represent my custom PostgreSQL object type (i created myself):

CREATE TYPE GOOGLE_ACCOUNT AS
(
  id    NUMERIC,
  token TEXT
);

And next structure is table in DB:

type Client struct {
     IdClient       uint64          `gorm:"primary_key"`
     Name           string
     PhotoUrl       string
     ApprovalNumber uint16
     Phone          string
     Password       string
     HoursOfNotice  int8
     Google         GoogleAccount
}

And my custom object nested in type Client and named as google. I've tried to read data by the next way:

var users model.Client
db.First(&users)

But unfortunately I can't read field google (have a default value). I don't want to create separate table with google_account, or make this structure as separated fields in client table or packed it as json (created separate entity, because this structure used not only in this table and I'm searching new ways, that get the same result, but more gracefully). The task is not to simplify the presentation of data in the table. I need to make the correct mapping of the object from postgres to the entity.

Right now I found one solution - implement Scanner to GoogleAccount. But value in the input method is []uint8. As I can suppose, []uint8 can cast to string, and after that I can parse this string. This string (that keep in db) look like (x,x) - where x - is value. Is the right way, to parse string and set value to object? Or is way to get this result by ORM?

Is the possible way, to read this data as nested structure object?

回答1:

It looks like you'll want to do two things with what you have: (1) update the model so you have the right relationship binding, and (2) use the .Preload() method if you're trying to get it to associate the data on read.

Model Changes

Gorm automatically infers relationships based on the name of the attributes in your struct and the name of the referenced struct. The problem is that Google attribute of type GoogleAccount isn't associating because gorm is looking for a type Google struct.

You're also missing a foreign key on GoogleAccount. How would the ORM know which GoogleAccount to associate with which Client? You should add a ClientId to your GoogleAccount struct definition.

Also, I would change the primary keys you're using to type uint since that's what gorm defaults to (unless you have a good reason not to use it)

If I were you, I would change my struct definitions to the following:

type Client struct {
     IdClient       uint            `gorm:"primary_key"`
     Name           string
     PhotoUrl       string
     ApprovalNumber uint16
     Phone          string
     Password       string
     HoursOfNotice  int8
     GoogleAccount  GoogleAccount    // Change this to `GoogleAccount`, the same name of your struct
}

type GoogleAccount struct {
     Id             uint
     ClientId       uint             // Foreign key
     Token          string
}

For more information on this, take a look at the associations documentation here: http://gorm.io/associations.html#has-one

Preloading associations

Now that you actually have them properly related, you can .Preload() get the nested object you want:

db.Preload("GoogleAccount").First(&user)

Using .Preload() will populate the user.GoogleAccount attribute with the correctly associated GoogleAccount based on the ClientId.

For more information on this, take a look at the preloading documentation: http://gorm.io/crud.html#preloading-eager-loading



回答2:

Right now I found one solution - implement Scanner to GoogleAccount. At input of the Scan method I got []uint8, that I cast to string and parse in the end. This string (that keeping in db) look like (x,x) - where x - is value. Of course, it is not correct way to achieve my goal. But I couldn't found other solution.

I highly recommended use classical binding by relationship or simple keeping these fields in table as simplest value (not as object).

But if you would like to experiment with nested object in table, you can look at my realization, maybe it would be useful for you: https://github.com/kirikzyusko1996/go-cleaning-api/blob/master/src/app/model/client.go