Gorm:如何将结构体存储在字段中

huangapple go评论78阅读模式
英文:

Gorm: How to store a struct in a field

问题

我正在尝试将类型为hedera.ContractID的Hedera合约ID保存到Gorm字段中,但是我遇到了错误:“invalid field found for struct github.com/hashgraph/hedera-sdk-go/v2.AccountID's field AliasKey: define a valid foreign key for relations or implement the Valuer interface”。

package contract

import (
	"fmt"

	"github.com/.../scanner/controllers/blockchain"
	database "github.com/.../scanner/db"
	model "github.com/.../scanner/models"
	"github.com/rs/xid"
	"gorm.io/gorm"
)

func DeployContract() *gorm.DB {

	// 连接数据库
	db, err := database.ConnectToDB()

	// 如果数据库连接失败
	if err != nil {
		panic(err)
	}

	// 初始化模型
	var modelContract model.Contract

	// 检查是否已部署合约
	if err := db.First(&modelContract); err.Error != nil {
		// 没有找到已部署的合约

		// 迁移模式
		db.AutoMigrate(&model.Contract{})

		// 部署合约
		contract, _ := blockchain.DeployContract()

		// 创建记录

		// 生成随机ID
		id := xid.New()

		// 创建
		db.Create(&model.Contract{
			Id:            id.String(),
			ContractId:    contract.Receipt.ContractID,
			GasUsed:       contract.CallResult.GasUsed,
			TransactionId: fmt.Sprint(contract.TransactionID),
			Timestamp:     contract.ConsensusTimestamp,
			ChargeFee:     fmt.Sprint(contract.TransactionFee),
			PayerAccount:  fmt.Sprint(contract.TransactionID.AccountID),
			Status:        fmt.Sprint(contract.Receipt.Status),
		})

	}

	return db
}

Gorm模型

package models

import (
	"time"

	"github.com/hashgraph/hedera-sdk-go/v2"
	"gorm.io/gorm"
)

type Contract struct {
	gorm.Model
	Id            string
	ContractId    *hedera.ContractID
	GasUsed       uint64
	TransactionId string
	Timestamp     time.Time
	ChargeFee     string
	PayerAccount  string
	Status        string
}

希望对你有所帮助!

英文:

I am trying to save an hederea contract ID of type *hedera.ContractID into a Gorm field but i get the error "invalid field found for struct github.com/hashgraph/hedera-sdk-go/v2.AccountID's field AliasKey: define a valid foreign key for relations or implement the Valuer interface"

package contract

import (
    "fmt"

    "github.com/.../scanner/controllers/blockchain"
    database "github.com/.../scanner/db"
    model "github.com/.../scanner/models"
    "github.com/rs/xid"
    "gorm.io/gorm"
)

func DeployContract() *gorm.DB {

	//connect to database
	db, err := database.ConnectToDB()

	//if db connection fails
	if err != nil {
		panic(err)
	}

	//init model
	var modelContract model.Contract

	//check if a contract has been deployed
	if err := db.First(&modelContract); err.Error != nil {
		//no deployment found

		//Migrate the schema
		db.AutoMigrate(&model.Contract{})

		//deploy contract
		contract, _ := blockchain.DeployContract()

		//create record

		// generate random id
		id := xid.New()

		// Create
		db.Create(&model.Contract{
			Id:            id.String(),
			ContractId:    contract.Receipt.ContractID,
			GasUsed:       contract.CallResult.GasUsed,
			TransactionId: fmt.Sprint(contract.TransactionID),
			Timestamp:     contract.ConsensusTimestamp,
			ChargeFee:     fmt.Sprint(contract.TransactionFee),
			PayerAccount:  fmt.Sprint(contract.TransactionID.AccountID),
			Status:        fmt.Sprint(contract.Receipt.Status),
		})

	}

	return db
}

Gorm Model

package models

import (
	"time"

	"github.com/hashgraph/hedera-sdk-go/v2"
	"gorm.io/gorm"
)

type Contract struct {
	gorm.Model
	Id            string
	ContractId    *hedera.ContractID
	GasUsed       uint64
	TransactionId string
	Timestamp     time.Time
	ChargeFee     string
	PayerAccount  string
	Status        string
}

答案1

得分: 0

对于自定义数据类型,您需要指定如何将值存储和从数据库中检索出来。这可以通过实现ScannerValuer接口来完成。

然而,由于hedera.ContractID是在另一个包中定义的,您需要创建自己的ContractID并实现这些接口。可以像这样进行操作:

type ContractID hedera.ContractID

type Contract struct {
    gorm.Model
    Id            string
    ContractId    *ContractID
    GasUsed       uint64
    TransactionId string
    Timestamp     time.Time
    ChargeFee     string
    PayerAccount  string
    Status        string
}     

func (c *ContractID) Scan(value interface{}) error {
  bytes, ok := value.([]byte)
  if !ok {
    return errors.New(fmt.Sprint("Failed to unmarshal ContractID value:", value))
  }

  return json.Unmarshal(bytes, c)
}

func (c ContractID) Value() (driver.Value, error) {
  return json.Marshal(c)
}

此外,在使用时将hedera.ContractID转换为model.ContractID。例如:

cID := model.ContractID(*contract.Receipt.ContractID)

// 创建
db.Create(&model.Contract{
    Id:            id.String(),
    ContractId:    &cID,
    GasUsed:       contract.CallResult.GasUsed,
    TransactionId: fmt.Sprint(contract.TransactionID),
    Timestamp:     contract.ConsensusTimestamp,
    ChargeFee:     fmt.Sprint(contract.TransactionFee),
    PayerAccount:  fmt.Sprint(contract.TransactionID.AccountID),
    Status:        fmt.Sprint(contract.Receipt.Status),
})
英文:

For custom data types, you need to specify how the value will be stored and retrieved from your database. This is done by implementing the Scanner and Valuer interfaces.

However, since hedera.ContractID is defined in another package, you will need to create your own ContractID and implement these interfaces. Something like this:

type ContractID hedera.ContractID

type Contract struct {
    gorm.Model
    Id            string
    ContractId    *ContractID
    GasUsed       uint64
    TransactionId string
    Timestamp     time.Time
    ChargeFee     string
    PayerAccount  string
    Status        string
}     

func (c *ContractID) Scan(value interface{}) error {
  bytes, ok := value.([]byte)
  if !ok {
    return errors.New(fmt.Sprint("Failed to unmarshal ContractID value:", value))
  }

  return json.Unmarshal(bytes, c)
}

func (c ContractID) Value() (driver.Value, error) {
  return json.Marshal(c)
}

Additionally, cast hedera.ContractID into model.ContractID wherever it is used. For example:

    cID := model.ContractID(*contract.Receipt.ContractID)

    // Create
    db.Create(&model.Contract{
        Id:            id.String(),
        ContractId:    &cID,
        GasUsed:       contract.CallResult.GasUsed,
        TransactionId: fmt.Sprint(contract.TransactionID),
        Timestamp:     contract.ConsensusTimestamp,
        ChargeFee:     fmt.Sprint(contract.TransactionFee),
        PayerAccount:  fmt.Sprint(contract.TransactionID.AccountID),
        Status:        fmt.Sprint(contract.Receipt.Status),
    })

huangapple
  • 本文由 发表于 2022年11月21日 01:58:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/74510576.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定