Code Monkey home page Code Monkey logo

Comments (20)

iTanken avatar iTanken commented on June 5, 2024 1

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

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024 1

还有就是 left join order by 的时候,生成的order by 字段名没有带表名导致执行失败,但是我不确定是不是驱动造成的,mysql是正常的

这个问题可以再详细描述一下吗?比如添加一些示例代码以及 MySQL 和 Oracle 的对比 SQL。

是我看错了, 是count语句生成的不一样: mysql 生成 select count(*) from xxx 但是 oracle 生成的 select count(*) from xxx by id , 我再看看, 有问题我再另提issue。

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 2024 1

注释到这几句就正常了, 没看明白这几行是用于什么场景的

用来在分页查询时如果没有指定排序方式的话使用主键作为默认排序方式。

在 Oracle 数据库中,如果你使用 OFFSET 进行分页查询,通常建议在查询中显式指定排序方式,尤其是在使用 OFFSETFETCH NEXT 进行分页时。

原因是,OFFSETFETCH NEXT 语法是和排序相关的,如果没有明确指定排序方式,查询结果的顺序可能是不确定的。在分页查询中,不确定的顺序可能导致在不同页之间的重复或遗漏的数据。

示例:

SELECT *
FROM your_table
ORDER BY your_column
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

在上面的示例中,ORDER BY your_column 明确指定了排序方式,确保在进行分页查询时结果是可预测的。如果你省略了 ORDER BY 子句,查询结果的顺序可能会随数据库的实现而变化,可能不符合你的预期。

因此,为了确保分页查询的结果是有序的,建议在使用 OFFSETFETCH NEXT 进行分页时,总是显式指定排序方式。

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 2024

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

image

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 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 去使用的

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 2024

好的,我明天再试一下

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024

感谢🙏

还有就是 left join order by 的时候,生成的order by 字段名没有带表名导致执行失败,但是我不确定是不是驱动造成的,mysql是正常的

oracle 版本是 19c

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024

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

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

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 2024

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

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

#8 (comment)

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 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:[email protected]: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
}

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 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

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024

否则字段名没

好的,感谢大佬解答

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

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 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 '注释中存在单引号''['']''';

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024

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

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 2024

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

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

    image

  • 测试结果:

    image

    image

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 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了

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024
type docCompareUserDo struct{ gen.DO }

type IDocCompareUserDo interface {
	gen.SubQuery
	Debug() IDocCompareUserDo
	WithContext(ctx context.Context) IDocCompareUserDo
	WithResult(fc func(tx gen.Dao)) gen.ResultInfo
	ReplaceDB(db *gorm.DB)
	ReadDB() IDocCompareUserDo
	WriteDB() IDocCompareUserDo
	As(alias string) gen.Dao
	Session(config *gorm.Session) IDocCompareUserDo
	Columns(cols ...field.Expr) gen.Columns
	Clauses(conds ...clause.Expression) IDocCompareUserDo
	Not(conds ...gen.Condition) IDocCompareUserDo
	Or(conds ...gen.Condition) IDocCompareUserDo
	Select(conds ...field.Expr) IDocCompareUserDo
	Where(conds ...gen.Condition) IDocCompareUserDo
	Order(conds ...field.Expr) IDocCompareUserDo
	Distinct(cols ...field.Expr) IDocCompareUserDo
	Omit(cols ...field.Expr) IDocCompareUserDo
	Join(table schema.Tabler, on ...field.Expr) IDocCompareUserDo
	LeftJoin(table schema.Tabler, on ...field.Expr) IDocCompareUserDo
	RightJoin(table schema.Tabler, on ...field.Expr) IDocCompareUserDo
	Group(cols ...field.Expr) IDocCompareUserDo
	Having(conds ...gen.Condition) IDocCompareUserDo
	Limit(limit int) IDocCompareUserDo
	Offset(offset int) IDocCompareUserDo
	Count() (count int64, err error)
	Scopes(funcs ...func(gen.Dao) gen.Dao) IDocCompareUserDo
	Unscoped() IDocCompareUserDo
	Create(values ...*model.DocCompareUser) error
	CreateInBatches(values []*model.DocCompareUser, batchSize int) error
	Save(values ...*model.DocCompareUser) error
	First() (*model.DocCompareUser, error)
	Take() (*model.DocCompareUser, error)
	Last() (*model.DocCompareUser, error)
	Find() ([]*model.DocCompareUser, error)
	FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.DocCompareUser, err error)
	FindInBatches(result *[]*model.DocCompareUser, batchSize int, fc func(tx gen.Dao, batch int) error) error
	Pluck(column field.Expr, dest interface{}) error
	Delete(...*model.DocCompareUser) (info gen.ResultInfo, err error)
	Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
	UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
	Updates(value interface{}) (info gen.ResultInfo, err error)
	UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
	UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
	UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
	UpdateFrom(q gen.SubQuery) gen.Dao
	Attrs(attrs ...field.AssignExpr) IDocCompareUserDo
	Assign(attrs ...field.AssignExpr) IDocCompareUserDo
	Joins(fields ...field.RelationField) IDocCompareUserDo
	Preload(fields ...field.RelationField) IDocCompareUserDo
	FirstOrInit() (*model.DocCompareUser, error)
	FirstOrCreate() (*model.DocCompareUser, error)
	FindByPage(offset int, limit int) (result []*model.DocCompareUser, count int64, err error)
	ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
	Scan(result interface{}) (err error)
	Returning(value interface{}, columns ...string) IDocCompareUserDo
	UnderlyingDB() *gorm.DB
	schema.Tabler
}

from gorm-oracle.

iTanken avatar iTanken commented on June 5, 2024

还有就是 left join order by 的时候,生成的order by 字段名没有带表名导致执行失败,但是我不确定是不是驱动造成的,mysql是正常的

这个问题可以再详细描述一下吗?比如添加一些示例代码以及 MySQL 和 Oracle 的对比 SQL。

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024
func (d Dialector) RewriteLimit(c clause.Clause, builder clause.Builder) {
	if limit, ok := c.Expression.(clause.Limit); ok {
		// if stmt, ok := builder.(*gorm.Statement); ok {
		// 	if _, ok := stmt.Clauses["ORDER BY"]; !ok {
		// 		s := stmt.Schema
		// 		_, _ = builder.WriteString("ORDER BY ")
		// 		if s != nil && s.PrioritizedPrimaryField != nil {
		// 			builder.WriteQuoted(s.PrioritizedPrimaryField.DBName)
		// 			_ = builder.WriteByte(' ')
		// 		} else {
		// 			_, _ = builder.WriteString("(SELECT NULL FROM ")
		// 			_, _ = builder.WriteString(d.DummyTableName())
		// 			_, _ = builder.WriteString(")")
		// 		}
		// 	}
		// }

		if offset := limit.Offset; offset > 0 {
			_, _ = builder.WriteString(" OFFSET ")
			_, _ = builder.WriteString(strconv.Itoa(offset))
			_, _ = builder.WriteString(" ROWS")
		}
		if limit := limit.Limit; limit != nil && *limit >= 0 {
			_, _ = builder.WriteString(" FETCH NEXT ")
			_, _ = builder.WriteString(strconv.Itoa(*limit))
			_, _ = builder.WriteString(" ROWS ONLY")
		}
	}
}

注释到这几句就正常了, 没看明白这几行是用于什么场景的

from gorm-oracle.

SheltonZhu avatar SheltonZhu commented on June 5, 2024

注释到这几句就正常了, 没看明白这几行是用于什么场景的

用来在分页查询时如果没有指定排序方式的话使用主键作为默认排序方式。

在 Oracle 数据库中,如果你使用 OFFSET 进行分页查询,通常建议在查询中显式指定排序方式,尤其是在使用 OFFSETFETCH NEXT 进行分页时。

原因是,OFFSETFETCH NEXT 语法是和排序相关的,如果没有明确指定排序方式,查询结果的顺序可能是不确定的。在分页查询中,不确定的顺序可能导致在不同页之间的重复或遗漏的数据。

示例:

SELECT *
FROM your_table
ORDER BY your_column
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

在上面的示例中,ORDER BY your_column 明确指定了排序方式,确保在进行分页查询时结果是可预测的。如果你省略了 ORDER BY 子句,查询结果的顺序可能会随数据库的实现而变化,可能不符合你的预期。

因此,为了确保分页查询的结果是有序的,建议在使用 OFFSETFETCH NEXT 进行分页时,总是显式指定排序方式。

明白了这个的作用了,但是为什么count函数会进到这里面来,count应该不需要排序, gorm/gen 的count,应该用的也是gorm的count函数。而且我有leftjoin,生成的语句没有 tablename前缀,所以不知道是哪张表的id

from gorm-oracle.

Related Issues (12)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.