Support delete with no bean (#1926)

Now you can use delete like this:

```
orm.Table("my_table").Where("id=?",1).Delete()
```

Reviewed-on: https://gitea.com/xorm/xorm/pulls/1926
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-committed-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
Lunny Xiao 2021-07-06 17:11:45 +08:00
parent a5030dc7a4
commit 8f64a78cd4
6 changed files with 87 additions and 42 deletions

View File

@ -245,35 +245,38 @@ for rows.Next() {
```Go ```Go
affected, err := engine.ID(1).Update(&user) affected, err := engine.ID(1).Update(&user)
// UPDATE user SET ... Where id = ? // UPDATE user SET ... WHERE id = ?
affected, err := engine.Update(&user, &User{Name:name}) affected, err := engine.Update(&user, &User{Name:name})
// UPDATE user SET ... Where name = ? // UPDATE user SET ... WHERE name = ?
var ids = []int64{1, 2, 3} var ids = []int64{1, 2, 3}
affected, err := engine.In("id", ids).Update(&user) affected, err := engine.In("id", ids).Update(&user)
// UPDATE user SET ... Where id IN (?, ?, ?) // UPDATE user SET ... WHERE id IN (?, ?, ?)
// force update indicated columns by Cols // force update indicated columns by Cols
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12}) affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ? // UPDATE user SET age = ?, updated=? WHERE id = ?
// force NOT update indicated columns by Omit // force NOT update indicated columns by Omit
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12}) affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ? // UPDATE user SET age = ?, updated=? WHERE id = ?
affected, err := engine.ID(1).AllCols().Update(&user) affected, err := engine.ID(1).AllCols().Update(&user)
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? // UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? WHERE id = ?
``` ```
* `Delete` delete one or more records, Delete MUST have condition * `Delete` delete one or more records, Delete MUST have condition
```Go ```Go
affected, err := engine.Where(...).Delete(&user) affected, err := engine.Where(...).Delete(&user)
// DELETE FROM user Where ... // DELETE FROM user WHERE ...
affected, err := engine.ID(2).Delete(&user) affected, err := engine.ID(2).Delete(&user)
// DELETE FROM user Where id = ? // DELETE FROM user WHERE id = ?
affected, err := engine.Table("user").Where(...).Delete()
// DELETE FROM user WHERE ...
``` ```
* `Count` count records * `Count` count records

View File

@ -271,6 +271,9 @@ affected, err := engine.Where(...).Delete(&user)
affected, err := engine.ID(2).Delete(&user) affected, err := engine.ID(2).Delete(&user)
// DELETE FROM user Where id = ? // DELETE FROM user Where id = ?
affected, err := engine.Table("user").Where(...).Delete()
// DELETE FROM user WHERE ...
``` ```
* `Count` 获取记录条数 * `Count` 获取记录条数

View File

@ -1202,10 +1202,10 @@ func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64
} }
// Delete records, bean's non-empty fields are conditions // Delete records, bean's non-empty fields are conditions
func (engine *Engine) Delete(bean interface{}) (int64, error) { func (engine *Engine) Delete(beans ...interface{}) (int64, error) {
session := engine.NewSession() session := engine.NewSession()
defer session.Close() defer session.Close()
return session.Delete(bean) return session.Delete(beans...)
} }
// Get retrieve one record from table, bean's non-empty fields // Get retrieve one record from table, bean's non-empty fields

View File

@ -241,3 +241,28 @@ func TestUnscopeDelete(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, has) assert.False(t, has)
} }
func TestDelete2(t *testing.T) {
assert.NoError(t, PrepareEngine())
type UserinfoDelete2 struct {
Uid int64 `xorm:"id pk not null autoincr"`
IsMan bool
}
assert.NoError(t, testEngine.Sync2(new(UserinfoDelete2)))
user := UserinfoDelete2{}
cnt, err := testEngine.Insert(&user)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
cnt, err = testEngine.Table("userinfo_delete2").In("id", []int{1}).Delete()
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
user2 := UserinfoDelete2{}
has, err := testEngine.ID(1).Get(&user2)
assert.NoError(t, err)
assert.False(t, has)
}

View File

@ -30,7 +30,7 @@ type Interface interface {
CreateUniques(bean interface{}) error CreateUniques(bean interface{}) error
Decr(column string, arg ...interface{}) *Session Decr(column string, arg ...interface{}) *Session
Desc(...string) *Session Desc(...string) *Session
Delete(interface{}) (int64, error) Delete(...interface{}) (int64, error)
Distinct(columns ...string) *Session Distinct(columns ...string) *Session
DropIndexes(bean interface{}) error DropIndexes(bean interface{}) error
Exec(sqlOrArgs ...interface{}) (sql.Result, error) Exec(sqlOrArgs ...interface{}) (sql.Result, error)

View File

@ -83,7 +83,7 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri
} }
// Delete records, bean's non-empty fields are conditions // Delete records, bean's non-empty fields are conditions
func (session *Session) Delete(bean interface{}) (int64, error) { func (session *Session) Delete(beans ...interface{}) (int64, error) {
if session.isAutoClose { if session.isAutoClose {
defer session.Close() defer session.Close()
} }
@ -92,20 +92,32 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
return 0, session.statement.LastError return 0, session.statement.LastError
} }
if err := session.statement.SetRefBean(bean); err != nil { var (
return 0, err condSQL string
condArgs []interface{}
err error
bean interface{}
)
if len(beans) > 0 {
bean = beans[0]
if err = session.statement.SetRefBean(bean); err != nil {
return 0, err
}
executeBeforeClosures(session, bean)
if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
processor.BeforeDelete()
}
condSQL, condArgs, err = session.statement.GenConds(bean)
} else {
condSQL, condArgs, err = session.statement.GenCondSQL(session.statement.Conds())
} }
executeBeforeClosures(session, bean)
if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
processor.BeforeDelete()
}
condSQL, condArgs, err := session.statement.GenConds(bean)
if err != nil { if err != nil {
return 0, err return 0, err
} }
pLimitN := session.statement.LimitN pLimitN := session.statement.LimitN
if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) { if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) {
return 0, ErrNeedDeletedCond return 0, ErrNeedDeletedCond
@ -156,7 +168,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
var realSQL string var realSQL string
argsForCache := make([]interface{}, 0, len(condArgs)*2) argsForCache := make([]interface{}, 0, len(condArgs)*2)
if session.statement.GetUnscoped() || table.DeletedColumn() == nil { // tag "deleted" is disabled if session.statement.GetUnscoped() || table == nil || table.DeletedColumn() == nil { // tag "deleted" is disabled
realSQL = deleteSQL realSQL = deleteSQL
copy(argsForCache, condArgs) copy(argsForCache, condArgs)
argsForCache = append(condArgs, argsForCache...) argsForCache = append(condArgs, argsForCache...)
@ -220,27 +232,29 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
return 0, err return 0, err
} }
// handle after delete processors if bean != nil {
if session.isAutoCommit { // handle after delete processors
for _, closure := range session.afterClosures { if session.isAutoCommit {
closure(bean) for _, closure := range session.afterClosures {
} closure(bean)
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok { }
processor.AfterDelete() if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
} processor.AfterDelete()
} else {
lenAfterClosures := len(session.afterClosures)
if lenAfterClosures > 0 {
if value, has := session.afterDeleteBeans[bean]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
session.afterDeleteBeans[bean] = &afterClosures
} }
} else { } else {
if _, ok := interface{}(bean).(AfterDeleteProcessor); ok { lenAfterClosures := len(session.afterClosures)
session.afterDeleteBeans[bean] = nil if lenAfterClosures > 0 && len(beans) > 0 {
if value, has := session.afterDeleteBeans[beans[0]]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
session.afterDeleteBeans[bean] = &afterClosures
}
} else {
if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
session.afterDeleteBeans[bean] = nil
}
} }
} }
} }