geektutu / blog

极客兔兔的博客,Coding Coding 创建有趣的开源项目。
https://geektutu.com
Apache License 2.0
166 stars 21 forks source link

动手写ORM框架 - GeeORM第四天 链式操作与更新删除 | 极客兔兔 #76

Open geektutu opened 4 years ago

geektutu commented 4 years ago

https://geektutu.com/post/geeorm-day4.html

7天用 Go语言/golang 从零实现 ORM 框架 GeeORM 教程(7 days implement golang object relational mapping framework from scratch tutorial),动手写 ORM 框架,参照 gorm, xorm 的实现。通过链式(chain)操作,支持查询条件(where, order by, limit 等)的叠加;实现记录的更新(update)、删除(delete)和统计(count)功能。

xiaoxfan commented 4 years ago

膜拜大佬

geektutu commented 3 years ago

膜拜大佬

@xiaoxfan 哈哈,感谢认可,希望对你有帮助~

boyl commented 3 years ago

链式调用太精巧了,Find, Delete,Update 等都是调用置后的。PS 这里的 SQL 语句合法性没有做限制,需要用户自己把握

haochen233 commented 3 years ago

这里是为了省代码吗,感觉可读性太差了。。。

s.clause.Set(clause.WHERE, append(append(vars, desc), args...)...)
wardseptember commented 3 years ago

这种链式调用不会导致SQL注入吗?

zagreos commented 3 years ago
func TestSession_DeleteAndCount(t *testing.T) {
    s := testRecordInit(t)
    affected, _ := s.Where("Name = ?", "Tom").Delete()
    count, _ := s.Count()

    if affected != 1 || count != 1 {
        t.Fatal("failed to delete or count")
    }
}

这里应该是count != 0逻辑才对,affected, _ := s.Where("Name = ?", "Tom").Delete()这个链式调用把clause.WHERE也Set了会导致后面s.Count()的时候把clause.WHERE条件也加进去,也就是SELECT count(*) FROM User WHERE Name = ? [Tom]。显然是 count 的值应该是 0 才对。

或者是否在clause.go 里面加一个 clear() 方法,在 Build 返回之前都调用一下?

xiaoheng14 commented 2 years ago

@SeanChan0901

func TestSession_DeleteAndCount(t *testing.T) {
  s := testRecordInit(t)
  affected, _ := s.Where("Name = ?", "Tom").Delete()
  count, _ := s.Count()

  if affected != 1 || count != 1 {
      t.Fatal("failed to delete or count")
  }
}

这里应该是count != 0逻辑才对,affected, _ := s.Where("Name = ?", "Tom").Delete()这个链式调用把clause.WHERE也Set了会导致后面s.Count()的时候把clause.WHERE条件也加进去,也就是SELECT count(*) FROM User WHERE Name = ? [Tom]。显然是 count 的值应该是 0 才对。

或者是否在clause.go 里面加一个 clear() 方法,在 Build 返回之前都调用一下?

xiaoheng14 commented 2 years ago

s.Raw().Exec()中的方法Exec有clear的了。

DurantVivado commented 2 years ago

lz可以拍个视频,手敲代码理解太累了

lcxc-lcxc commented 2 years ago
func TestSession_DeleteAndCount(t *testing.T) {
    s := testRecordInit(t)
    affected, _ := s.Where("Name = ?", "Tom").Delete()
    count, _ := s.Count()

    if affected != 1 || count != 1 {
        t.Fatal("failed to delete or count")
    }
}

这里执行两个sql语句,难道不需要清空s.clause里面的内容吗?我执行的话会出错,因为Count里面还用上了Where子句。

我在clause.Build函数里面添加一个清除操作,才能不会报错。作者是在其它地方添加了操作吗?

func (c *Clause)Build(orders ...Type)(string,[]interface{})  {
    ......
    defer func() {
        c.sql=nil
        c.sqlVars=nil
    }()
    .....
}
niconical commented 1 year ago

@lcxc-lcxc

func TestSession_DeleteAndCount(t *testing.T) {
  s := testRecordInit(t)
  affected, _ := s.Where("Name = ?", "Tom").Delete()
  count, _ := s.Count()

  if affected != 1 || count != 1 {
      t.Fatal("failed to delete or count")
  }
}

这里执行两个sql语句,难道不需要清空s.clause里面的内容吗?我执行的话会出错,因为Count里面还用上了Where子句。

我在clause.Build函数里面添加一个清除操作,才能不会报错。作者是在其它地方添加了操作吗?

func (c *Clause)Build(orders ...Type)(string,[]interface{})  {
  ......
  defer func() {
      c.sql=nil
      c.sqlVars=nil
  }()
  .....
}

确实需要手动clear一下

ShiMaRing commented 1 year ago

@xiaoheng14 s.Raw().Exec()中的方法Exec有clear的了。

那个clear清空的是stringBuilder中缓存的sql语句,而不是子句中的各个条件

lv997 commented 5 months ago

@haochen233 这里是为了省代码吗,感觉可读性太差了。。。

s.clause.Set(clause.WHERE, append(append(vars, desc), args...)...)

只是提供了一种思路,让初学者入门而已。配合着debug调试就好了。真正使用ORM不会这么繁琐的。例如调用laravel的时候都是高度封装成->where(field,value)的形式