Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
207 views
in Technique[技术] by (71.8m points)

mysql - How to prevent gorm from converting custom integer types into strings?

I have troubles while using gorm with custom types that have integer properties. Gorm tends to convert the integer values into strings for me. There are two separate problems:

Problem 1:

I have a custom type defined as follows:

type ClientType uint8

const (
    USER ClientType = iota
    SERVER
)

func (t ClientType) String() string {
    return [...]string{"User", "Service"}[t]

And then I have a ORM struct for Client defined like this:

type Client struct {
    ClientID uint64 `gorm:"primaryKey"`
    UserID uint64
    ClientType ClientType
    CreatedAt time.Time
}

When calling db.Create(&client), gorm automatically invokes the String() method on ClientType, and causes a data type mismatch in MySQL where I intend to store ClientType in a TINYINT column called client_type.

Problem 2:

So I thought if I can't figure out how to override the automatic calling of the String() method, I simply renamed the method to ToString() and call it when I need it. Now gorm can't invoke it any more, but instead, it casts the integer values into numeric strings instead. So USER which is 0, will now become '0' in the resulting SQL statement, and SERVER will become '1', although MySQL is able to cast the strings back to integers.

I still wonder what I did wrong to make gorm think I wanted these conversions.

  1. Is there a way to override the calling of String(), so I can still name the method conventionally?
  2. Is it the use of uint8 that made gorm converts the int to strings, since the other numeric values (ClientID and UserID) using uint64 were not affected by the issue? Is it some sort of caching of the DB schema that made gorm remember the old schema where client_type used to be an ENUM('User', 'Service') column?
question from:https://stackoverflow.com/questions/65930751/how-to-prevent-gorm-from-converting-custom-integer-types-into-strings

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

As per gorm for custom types Value and Scan need to be implemented.

You can try specifying type in struct (replace <TYPE> with column type) too.

type Client struct {
    ClientID   uint64 `gorm:"primaryKey"`
    UserID     uint8
    ClientType ClientType `gorm:"type:<TYPE>"`
    CreatedAt  time.Time
}

String() does not seems to be issue as it is not called during creates, but only during finds.

With db.LogMode(true), it is called during create also, but that seems to be for sql query logging and not for sending to DB.

With Log Mode off

    db.LogMode(false)
    fmt.Println("Creating")
    db.Create(&Client{ClientID: 9, UserID: 8, ClientType: USER, CreatedAt: time.Now()})
    fmt.Println("Created")

    fmt.Println("Finding")
    db.First(&client)
    fmt.Printf("Found %v
", client)

output

Creating
Created
Finding
String() called with 0
Found {9 8 User 2021-01-28 11:41:51.355633057 +0530 +0530}

With Log Mode on

    db.LogMode(true)
    fmt.Println("Creating")
    db.Create(&Client{ClientID: 9, UserID: 8, ClientType: USER, CreatedAt: time.Now()})
    fmt.Println("Created")

    fmt.Println("Finding")
    db.First(&client)
    fmt.Printf("Found %v
", client)

Output:

Creating
String() called with 0
[2021-01-28 11:39:30]  [0.95ms]  INSERT INTO "clients" ("client_id","user_id","client_type","created_at") VALUES (9,8,'User','2021-01-28 11:39:30')  
[1 rows affected or returned ] 
Created
Finding
[2021-01-28 11:39:30]  [1.49ms]  SELECT * FROM "clients"   LIMIT 1  
[1 rows affected or returned ] 
String() called with 0
Found {9 8 User 2021-01-28 11:42:31.245628274 +0530 +0530}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...