datatypes icon indicating copy to clipboard operation
datatypes copied to clipboard

JSONType field Data: define a valid foreign key for relations or implement the Valuer/Scanner

Open liyuan1125 opened this issue 1 year ago • 4 comments

type (
	User struct {
		Name string `json:"name"`
		Age  int    `json:"age"`
	}

	TestTable struct {
		ID   uint64
		Data datatypes.JSONType[*User]
	}
)

func (*TestTable) TableName() string {
	return "test_table"
}


 db.Create(&TestTable{Data: datatypes.JSONType[*User]{Data: &User{Name: "name", Age: 18}}})

row := &datatypes.JSONType[*User]{}

db.Limit(1).Order("id DESC").Pluck("data", row)
// output
// invalid field found for struct gorm.io/datatypes.JSONType[*main.User]'s field Data: define a valid foreign key for relations or implement the Valuer/Scanner interface

fmt.Println(row.Data)

row := &TestTable{}

db.Limit(1).Order("id DESC").Find(row)
	
fmt.Println(row.Data.Data)
// ok

liyuan1125 avatar Mar 30 '23 15:03 liyuan1125

我来看下这个。

alingse avatar Apr 06 '23 08:04 alingse

@liyuan1125 I have test, your code miss db.Model(&TestTable{}) part.

I have create a gist here https://gist.github.com/alingse/adbcd450ea6760bac1d41faa07610870#file-queryjsontype-go-L44-L53 and the log

	// ok
	row := &TestTable{}
	db.Limit(1).Order("id DESC").Find(row)
	// find all row  &{name 18}
	fmt.Println("find all row ", row.Data.Data)

	// ok
	var field datatypes.JSONType[*User]
	err = db.Model(&TestTable{}).Limit(1).Order("id DESC").Pluck("data", &field).Error
	// find field  &{name 18} <nil>
	fmt.Println("find field ", field.Data, err)

	// ok
	var fullRow TestTable
	err = db.Model(&TestTable{}).Limit(1).Order("id DESC").Pluck("data", &fullRow.Data).Error
	// find field in row  <nil> &{name 18}
	fmt.Println("find field in row ", err, fullRow.Data.Data)

it query ok, but really got some error log.

[error] invalid field found for struct gorm.io/datatypes.JSONType[*main.User]'s field Data: define a valid foreign key for relations or implement the Valuer/Scanner interface
find field in row  <nil> &{name 18}

查询是正常的,只是会多一些 error log

我感觉是 gorm 首先尝试把 JSONType[*User] 当作 Model 来解析, 尝试这个 Model 的每个 Struct Field,然后失败后再完整当作单个的 field 来查询。

但是我也比较困惑。看调用链路 ,这个 field 的 Datatype 肯定是设置了的,是"json" 但是还是走入了这个分支

https://github.com/go-gorm/gorm/blob/532e9cf4ccce927249bcb102c09e4a9093aae4fe/schema/schema.go#L281-L283

			if field.DataType == "" && (field.Creatable || field.Updatable || field.Readable) {
				if schema.parseRelation(field); schema.err != nil {
					return schema, schema.err

再走入了这里 https://github.com/go-gorm/gorm/blob/532e9cf4ccce927249bcb102c09e4a9093aae4fe/schema/relationship.go#L86

目前没有处理 // case guessEmbeddedHas: 所以会有 error log

我看下有什么好的设置可以把 JSONType 当作单个 Field 而不当作 Model 去猜测

alingse avatar Apr 06 '23 10:04 alingse

我测了下,可以改进,就是会有点 break change

type JSONType[T any] struct {
	data T
}

func (j JSONType[T]) GetData() T {
	return j.data
}

这样就不会出现上面的 error log 了 晚点我提交一下 , 之前提交的时候没有测试到 cc @jinzhu

alingse avatar Apr 06 '23 10:04 alingse

the fix MR merged, and no error log anymore,

but your Pluck usage might wrong.

use Pluck with JSONType[T]

	// ok
	var field []datatypes.JSONType[*User]
	err = db.Model(&TestTable{}).Limit(1).Order("id DESC").Pluck("info", &field).Error
	// find field  &{name 18} <nil>
	fmt.Println("find field ", field[0].Data(), err)

use Pluck with JSONSlice[T]

	// ok
	var parents []datatypes.JSONSlice[*User]
	err = db.Model(&TestTable{}).Limit(1).Order("id DESC").Pluck("parent", &parents).Error
	fmt.Println("find parents in slice ", err, parents[0], *parents[0][0], *parents[0][1])

they both query ok. see my show case gist https://gist.github.com/alingse/a3187af45d516d591c7a077ed8c739f9

alingse avatar Apr 11 '23 03:04 alingse