This is a creation in Article, where the information may have evolved or changed.
In the beego1.6.1 version ORM did not provide insertorupdate, but the project when they encountered this requirement, Gu wrote a own implementation, temporarily only support MySQL and Postgres. The realization principle is that the data comes with the function statement that can realize insertorupdate.
mysql:- ON DUPLICATE KEY UPDATE
Postgres:- ON CONFLICT DO UPDATE SET
Then go to the ORM implementation and assemble the SQL statement yourself.
OK, light code:
Func (d *dbbase) insertorupdate (q Dbquerier, MI *modelinfo,ind reflect. Value, TZ *time. Location, dn string, args ... string)
(Int64, error) {
IOUSTR: = "" MySQL: = "MySQL" Postgres: = "Postgres" Argsmap: = map[string]string{}if DN = = MySQL {ioustr = "on DUPLICATE KEY UPDATE "} else if DN = = Postgres && len (args) > 0 {args0 = args[0] Ioustr = FMT. Sprintf ("On CONFLICT (%s) does UPDATE SET", Args0)} else {return 0, FMT. Errorf ("'%s ' nonsupport insert or update in Beego", dn)}for _, V: = Range args {kv: = strings. Split (V, "=") If Len (kv) = = 2 {argsmap[kv[0]] = kv[1]}}ismulti: = falsenames: = Make ([]string, 0, Len (mi.fi Elds.dbcols)-1) Q: = D.ins.tablequote () values, err: = D.collectvalues (MI, Ind, Mi.fields.dbcols, True, True, &names, t Z) If Err! = Nil {return 0, Errmarks: = Make ([]string, Len (names)) Updatevalues: = Do ([]interface{}, 0) Updates: = Make ([]string, Len (names)) var conflitvalue interface{}for I, V: = range names {Marks[i] = "?" VALUESTR: = Argsmap[v] if v = = args0 {conflitvalue = values[i]} if valuestr! = "" {switch DN { Case MySQL: Updates[i] = v + "=" + valuestr break case postgres:if Conflitvalue! = Nil { Updates[i] = fmt. Sprintf ("%s= (select%s from%s where%s =?)", V, Valuestr, mi.table, args[0]) updatevalues = append (updat Evalues, Conflitvalue)} else {return 0, FMT. Errorf ("'%s ' must is in front of '%s ' in your struct", args[0], V)} break}} else { Updates[i] = v + "=?" Updatevalues = Append (Updatevalues, values[i])}values = append (values, updatevalues ...) Sep: = fmt. Sprintf ("%s,%s", Q, q) Qmarks: = Strings. Join (Marks, ",") qupdates: = Strings. Join (Updates, ",") Columns: = Strings. Join (names, sep) Multi: = Len (values)/len (names) if Ismulti {qmarks = strings. Repeat (qmarks+ "), (", multi-1) + qmarks}query: = Fmt. Sprintf ("INSERT into%s%s%s (%s%s%s) VALUES (%s)%s" +qupdates, Q, mi.table, q, q, columns, q, Qmarks, ioustr) if Ismulti | |!d.ins.hasreturningid (MI, &querY) {res, err: = q.exec (query, Values ...) If Err = = Nil {if Ismulti {return res. Rowsaffected ()} return res. Lastinsertid ()} return 0, Err}row: = Q.queryrow (query, Values ...) var id int64err = row. Scan (&ID) return ID, err}
This is the full logic of the implementation of the function, of course, to use insertorupdate in the Beego ORM has some other work to do, first of all, this code should be added to the-beego/orm文件夹下的db.go文件中
And then orm.go Add it in the file
Func (o *orm) insertorupdate (MD Interface{},colconflitandargs ... string) (Int64, error) {
mi, ind := o.getMiInd(md, true)id, err := o.alias.DbBaser.InsertOrUpdate(o.db, mi, ind, o.alias.TZ, o.alias.DriverName, colConflitAndArgs...)if err != nil { return id, err }o.setPk(mi, ind, id)return id, nil}
Again intypes.go文件中的type Ormer interface和type dbBaser interface中分别添加
* * InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error) with
**InsertOrUpdate(dbQuerier, *modelInfo, reflect.Value, *time.Location, string, ...string) (int64, error)
Okay, now it's done. You can use the Inssertorupdate function
Gca
Mysql:
Func ioufinish (all *finish) Int64 {
db := orm.NewOrm()db.Using("mysql")r, e := db.InsertOrUpdate(all, "step=step+1")if e != nil { fmt.Println(e) return 0}fmt.Println(r)return r}
This function has a primary key or unique key conflict when entering or exiting the data, the update operation is performed, where the step column performs the + self-increment operation, and the other columns are update by the value in model. Where the "step=step+1" format data can be multiple or not, this format is used only for the self-increment operation
Postgres
Func ioufinish (all *finish) Int64 {
db := orm.NewOrm()db.Using("postgres")r, e := db.InsertOrUpdate(all,"confilctColumnName" "step=step+1")if e != nil { fmt.Println(e) return 0}fmt.Println(r)return r}
When manipulating the Postgres database, you must specify the column name of the conflicting column you expect in the first parameter after the model (due to the SQL statement that implements this function and the database version must be greater than 9.5 because the implemented statement is released by the 9.5 version), the other is consistent with MySQL.
Tip: When using a self-increment operation, it is best not to increment the primary key or unique key, which may cause errors.