xormのオートインクリメントタグをsliceで利用した時に、痒いところに手が届かない話

2020-01-05

xormのオートインクリメントタグをsliceで利用した時に、痒いところに手が届かない話

この記事はGo2 Advent Calendar 2019に参加しています。

まとめ

xormのオートインクリメントタグをsliceで利用する時、
インサート後にオートインクリメント値を再利用する場合は、
同じsliceを回すループ内でアクセスしないと初期化されて取得できない。

スライスではなく単体で構造体を宣言している場合は、初期化されずそのまま再利用可能です。

構造体を定義

type SampleOutsideInput struct {
	Items  []*SampleOutsideItemInput `json:"items"` // slice型を定義
}

type SampleOutsideItemInput struct {
	ID      uint64  `xorm:"pk autoincr" json:"-"` // こいつ
	Number  uint64  `json:"repairNumber""`
}

先にインサートしてオートインクリメントIDを再利用しようと取得すると取れない

インサートしてみる

func (u *SampleOutside) Create(params *model.SampleOutsideInput) (bool error) {

session := u.engine.NewSession()
	defer session.Close()

	// 楽してsliceをインサートしよう
	_, err = session.Table("t_sample_items").Insert(&params.Items)
	if err != nil {
		return err
	}

オートインクリメント指定したIDをKeyに再利用して別テーブルにインサートしようとするとエラー

for _, v := range params.Items {
		_, err = session.Table("t_sample_histories").
			Insert(&model.EquipmentHistoriesInput{
				TransactionID:           v.ID, // こいつが取得できずにエラー
				TransactionNumber:       v.SampleNumber,
				TransactionDetailNumber: v.SampleDetailNumber,
			})
		if err != nil {
			return err
		}
	}

どうすれば取れるか

同じsliceを回すループの中でアクセスすれば取得できる

session := u.engine.NewSession()
		defer session.Close()

		for _, v := range params.Items {

			// ループ外でインサートしてたのをループ内に移動
			_, err := session.Table("t_sample_items").Insert(v)
			if err != nil {
				return err
			}

			// 同じループ内でアクセスすると
			_, err = session.Table("t_sample_histories").
				Insert(&model.EquipmentHistoriesInput{
					TransactionID:           v.ID, // 取得できる
					TransactionNumber:       v.SampleNumber,
					TransactionDetailNumber: v.SampleDetailNumber,
				})
			if err != nil {
				return err
			}
		}
	}