Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用 gorm.io/gen 创建数据时无法获取自增主键返回值(insert 语句主键 id 获取不到) #11

Closed
SheltonZhu opened this issue Jan 17, 2024 · 20 comments
Assignees
Labels
bug Something isn't working enhancement New feature or request

Comments

@SheltonZhu
Copy link

SheltonZhu commented Jan 17, 2024

INSERT INTO doc_compare_user (name,account,password,status,ctm,utm,type,admin_id,note,expire_time,deleted,source_id,sso_user_unique_id) VALUES ('test','test','d9d7392be643cc709bbcb403e441b163',1,'2024-01-17 18:08:00.598','2024-01-17 18:08:00.598',0,20230831,'','2121-01-01 00:00:00',-1,-1,'3f752d69-bf9b-4f2f-8f4f-d34d9a201bfc') /*--*/RETURNING id INTO '{{} 0xc001688a90 false}' /*-sql.Out{}-*/

我的主键是int32 , insertTo.Kind() = 22, 是指针类型

func getDefaultValues(db *gorm.DB, idx int) {
	insertTo := db.Statement.ReflectValue
	switch insertTo.Kind() {
	case reflect.Slice, reflect.Array:
		insertTo = insertTo.Index(idx)
	default:
	}

	for _, val := range db.Statement.Vars {
		switch v := val.(type) {
		case sql.Out:
			switch insertTo.Kind() {
			case reflect.Slice, reflect.Array:
				for i := insertTo.Len() - 1; i >= 0; i-- {
					rv := insertTo.Index(i)
					if reflect.Indirect(rv).Kind() != reflect.Struct {
						break
					}

					_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
					if isZero {
						_ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, v.Dest))
					}
				}
			case reflect.Struct:
				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, insertTo)
				if isZero {
					_ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, insertTo, v.Dest))
				}
			default:
                               
                                 // 会跳到这里 insertTo.Kind()  = 22, 是指针类型
				}
			}
		default:
		}
	}
}

企业微信截图_17054870027306

@iTanken
Copy link
Member

iTanken commented Jan 17, 2024

请问你用的哪个版本?我用最新版 v1.5.18 测试 int32 类型的主键是返回了值的:

image

@SheltonZhu
Copy link
Author

SheltonZhu commented Jan 17, 2024

请问你用的哪个版本?我用最新版 v1.5.18 测试 int32 类型的主键是返回了值的:

github.com/godoes/gorm-oracle v1.5.18
type DocCompareUser struct {
	ID              int32      `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`                          // 自增id
	Name            *string    `gorm:"column:name" json:"name"`                                                    // 用户名称
	Account         *string    `gorm:"column:account" json:"account"`                                              // 账户名称
	Password        *string    `gorm:"column:password" json:"password"`                                            // 用户密码md5
	Status          *int32     `gorm:"column:status" json:"status"`                                                // 用户状态,1 正常 -1 删除 2 停用
	Ctm             *time.Time `gorm:"column:ctm" json:"ctm"`                                                      // 创建时间
	Utm             *time.Time `gorm:"column:utm" json:"utm"`                                                      // 更新时间
	Type            *int32     `gorm:"column:type" json:"type"`                                                    // 用户类型
	AdminID         int32      `gorm:"column:admin_id;not null" json:"admin_id"`                                   // 暂无特别含义,可以忽略
	Note            string     `gorm:"column:note;not null" json:"note"`                                           // 账号备注
	ExpireTime      time.Time  `gorm:"column:expire_time;not null;default:2121-01-01 00:00:00" json:"expire_time"` // 过期时间
	Deleted         int32      `gorm:"column:deleted;not null;default:-1" json:"deleted"`                          // 不为-1表示已经删除
	SourceID        int32      `gorm:"column:source_id;not null;default:-1" json:"source_id"`                      // 来源类型, -1 代表原生用户, 其他代表其他sso登录方式的配置id
	SsoUserUniqueID string     `gorm:"column:sso_user_unique_id;not null" json:"sso_user_unique_id"`               // 其他方式创建的用户的唯一标识
}

我是通过 gorm/gen 去使用的

@iTanken

This comment was marked as outdated.

@SheltonZhu

This comment was marked as off-topic.

@SheltonZhu
Copy link
Author

SheltonZhu commented Jan 17, 2024

请问你用的哪个版本?我用最新版 v1.5.18 测试 int32 类型的主键是返回了值的:

还有一个问题想请教一下,定义struct的时候,gorm 的tag是小写下划线,oracle创建数据库的时候是大写下划线,go-ora驱动的 rows.Columns方法返回的是全大写,我看gorm 绑定字段的时候是去找tag也就是dbname和keyname,导致绑定不上数据,但是你给的这个似乎没问题?

@iTanken
Copy link
Member

iTanken commented Jan 18, 2024

还有一个问题想请教一下,定义struct的时候,gorm 的tag是小写下划线,oracle创建数据库的时候是大写下划线,go-ora驱动的 rows.Columns方法返回的是全大写,我看gorm 绑定字段的时候是去找tag也就是dbname和keyname,导致绑定不上数据,但是你给的这个似乎没问题?

可以参考这个问题的回答:

#8 (comment)

@SheltonZhu
Copy link
Author

SheltonZhu commented Jan 18, 2024

请问你用的哪个版本?我用最新版 v1.5.18 测试 int32 类型的主键是返回了值的:

还有一个问题想请教一下,定义struct的时候,gorm 的tag是小写下划线,oracle创建数据库的时候是大写下划线,go-ora驱动的 rows.Columns方法返回的是全大写,我看gorm 绑定字段的时候是去找tag也就是dbname和keyname,导致绑定不上数据,但是你给的这个似乎没问题?

可以参考这个问题的回答:

#8 (comment)

我使用的配置如下, sql是可以执行的, 结果也能拿得到, 是在rows 绑定到 struct的过程中,没有绑定上, 通过调试发现 在 gorm/scan.gofunc Scan(rows Rows, db *DB, mode ScanMode) 中会去获取go-ora的列名 columns, _ = rows.Columns() 拿到的都是全大写, 然后去 sch.LookUpField(column),寻找,但是只在FieldsByDBNameFieldsByName中找, FieldsByDBName中是gorm 的columu, tag,全小写, 所以找不到,最后没有把数据绑定上.

	options := map[string]string{
		"CONNECTION TIMEOUT": "90",
		"LANGUAGE":           "SIMPLIFIED CHINESE",
		"TERRITORY":          "CHINA",
		"SSL":                "false",
		"lob fetch":          "post",
	}
	// oracle://user:password@127.0.0.1:1521/database
	url := oracle.BuildUrl(opts.Host, opts.Port, opts.Database, opts.Username, opts.Password, options)
	return oracle.New(oracle.Config{
		DSN:                 url,
		IgnoreCase:          false, // query conditions are not case-sensitive
		NamingCaseSensitive: false, // whether naming is case-sensitive
	}), nil
var (
		columns, _          = rows.Columns()
		values              = make([]interface{}, len(columns))
		initialized         = mode&ScanInitialized != 0
		update              = mode&ScanUpdate != 0
		onConflictDonothing = mode&ScanOnConflictDoNothing != 0
	)
func (schema Schema) LookUpField(name string) *Field {
	if field, ok := schema.FieldsByDBName[name]; ok {
		return field
	}
	if field, ok := schema.FieldsByName[name]; ok {
		return field
	}
	return nil
}

@iTanken
Copy link
Member

iTanken commented Jan 18, 2024

我使用的配置如下, sql是可以执行的, 结果也能拿得到, 是在rows 绑定到 struct的过程中,没有绑定上, 通过调试发现 在 gorm/scan.gofunc Scan(rows Rows, db *DB, mode ScanMode) 中会去获取go-ora的列名 columns, _ = rows.Columns() 拿到的都是全大写, 然后去 sch.LookUpField(column),寻找,但是只在FieldsByDBNameFieldsByName中找, FieldsByDBName中是gorm 的columu, tag,全小写, 所以找不到,最后没有把数据绑定上.

启用 NamingCaseSensitive 后会使用双引号包裹字段名,自动迁移表结构时创建的字段才会是小写的,否则字段名没有加双引号 Oracle 数据库默认创建大写字段,就不能跟 tag 指定的小写字段匹配上。所以要么 tag 改成大写,要么启用 NamingCaseSensitive

@SheltonZhu
Copy link
Author

否则字段名没

好的,感谢大佬解答

我这边因为某些原因不能使用自动迁移表结构功能, 创建的都是大写字段,目前是写了了插件在FieldsByDBName中添加了大写的key来解决的

@iTanken
Copy link
Member

iTanken commented Jan 18, 2024

感谢大佬解答

额,互相交流,没必要搞这些名词。这个库本身还不够完善,有人反馈问题我也很感谢。

我这边因为某些原因不能使用自动迁移表结构功能, 创建的都是大写字段

如果是使用 SQL 脚本创建表结构,想要小写表名和字段名可以手动加双引号,比如:

创建小写表名和字段名
-- drop table SYSTEM."test_user";
create table SYSTEM."test_user" (
    "id"                   NUMBER generated as identity primary key,
    "name"                 VARCHAR2(50),
    "account"              VARCHAR2(50),
    "password"             VARCHAR2(512),
    "email"                VARCHAR2(128),
    "phone_number"         VARCHAR2(15),
    "sex"                  CHAR,
    "birthday"             TIMESTAMP(6) WITH TIME ZONE,
    "user_type"            NUMBER,
    "enabled"              NUMBER(1),
    "remark"               VARCHAR2(1024),
    "uid"                  VARCHAR2(50),
    "add_new_column"       VARCHAR2(100),
    "comment_single_quote" VARCHAR2(1024)
);

comment on table SYSTEM."test_user" is '用户信息表';
comment on column SYSTEM."test_user"."id" is '自增 ID';
comment on column SYSTEM."test_user"."name" is '用户姓名';
comment on column SYSTEM."test_user"."account" is '登录账号';
comment on column SYSTEM."test_user"."password" is '登录密码(密文)';
comment on column SYSTEM."test_user"."email" is '邮箱地址';
comment on column SYSTEM."test_user"."phone_number" is 'E.164';
comment on column SYSTEM."test_user"."sex" is '性别';
comment on column SYSTEM."test_user"."birthday" is '生日';
comment on column SYSTEM."test_user"."user_type" is '用户类型';
comment on column SYSTEM."test_user"."enabled" is '是否可用';
comment on column SYSTEM."test_user"."remark" is '备注信息';
comment on column SYSTEM."test_user"."uid" is '用户身份标识';
comment on column SYSTEM."test_user"."add_new_column" is '测试添加新字段';
comment on column SYSTEM."test_user"."comment_single_quote" is '注释中存在单引号''['']''';

@SheltonZhu
Copy link
Author

是的,现在在想办法批量加引号😂

@iTanken
Copy link
Member

iTanken commented Jan 18, 2024

我用 Oracle19c 和你给的结构体测试也返回了 ID,确定你数据库里的 ID 字段是自增的吗?DocCompareUser 结构体有没有 AfterFind 类的钩子方法或其他处理?

使用 Oracle19c 和 DocCompareUser 结构体测试结果
  • 数据库表自增列:

    image

  • 测试结果:

    image

    image

@SheltonZhu
Copy link
Author

SheltonZhu commented Jan 18, 2024

我用 Oracle19c 和你给的结构体测试也返回了 ID,确定你数据库里的 ID 字段是自增的吗?DocCompareUser 结构体有没有 AfterFind 类的钩子方法或其他处理?

使用 Oracle19c 和 DocCompareUser 结构体测试结果

CREATE TABLE "doc_compare_user" (
    "id" NUMBER(10, 0) GENERATED BY DEFAULT ON NULL AS IDENTITY START WITH 143 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE,
    "name" VARCHAR2(255 CHAR),
    "account" VARCHAR2(255 CHAR),
    "password" VARCHAR2(255 CHAR),
    "status" NUMBER(10, 0),
    "ctm" TIMESTAMP(0),
    "utm" TIMESTAMP(0),
    "type" NUMBER(10, 0),
    "admin_id" NUMBER(10, 0) NOT NULL,
    "note" VARCHAR2(10 CHAR),
    "expire_time" TIMESTAMP(0) NOT NULL,
    "deleted" NUMBER(10, 0) NOT NULL,
    "source_id" NUMBER(3, 0) NOT NULL,
    "sso_user_unique_id" VARCHAR2(255 CHAR) NOT NULL
);

COMMENT ON COLUMN "doc_compare_user"."id" IS '自增id';

创建语句是这么写的(这个是替换引号后的, 响应的insert语句也要加上"")

没有写过 AfterFind钩子, gorm/gen 生成的代码里也没有看到

如果你那边没有问题, 那大概率是gorm/gen这个库做了什么吧...把 insertTo.Kind() 的类型变成了 指针

			case reflect.Pointer:
				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, insertTo)
				if isZero {
					_ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, insertTo, v.Dest))
				}
				

我加了这句就可以赋值id了

@SheltonZhu

This comment was marked as resolved.

@iTanken
Copy link
Member

iTanken commented Jan 18, 2024

@SheltonZhu https://github.com/godoes/gorm-oracle/releases/tag/v1.5.19 已修复并发布,有空可以试一下。

@iTanken

This comment was marked as off-topic.

@iTanken iTanken self-assigned this Jan 18, 2024
@iTanken iTanken added bug Something isn't working enhancement New feature or request labels Jan 18, 2024
@SheltonZhu

This comment was marked as off-topic.

@SheltonZhu

This comment was marked as off-topic.

@iTanken

This comment was marked as off-topic.

@SheltonZhu

This comment was marked as off-topic.

iTanken added a commit that referenced this issue Jan 19, 2024
@iTanken iTanken changed the title insert 语句主键id获取不到 insert 语句主键 id 获取不到(使用 gorm.io/gen 创建数据时无法获取自增主键返回值) Jan 19, 2024
@iTanken iTanken changed the title insert 语句主键 id 获取不到(使用 gorm.io/gen 创建数据时无法获取自增主键返回值) 使用 gorm.io/gen 创建数据时无法获取自增主键返回值(insert 语句主键 id 获取不到) Jan 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants