XORM - Go ORM: advanced usage

June 16, 2014

Transaction

Sample code 1

This part is based on last post XORM - Go ORM: basic guide and make some improvements in sample code. In the last post, the transfer part didn’t use transcation to make operation safe, and now it is:

// Create Session object.
sess := x.NewSession()
defer sess.Close()
// Start transcation.
if err = sess.Begin(); err != nil {
    return err
}

if _, err = sess.Update(a1); err != nil {
    // Roll back when error occurs.
    sess.Rollback()
    return err
} else if _, err = sess.Update(a2); err != nil {
    sess.Rollback()
    return err
}
// Commit transcation.
return sess.Commit()
  • First of all, call method x.NewSession to get a session object, then do not forget use defer to close it when return.
  • Use method sess.Begin to tell xorm you are going to make everything after this be in the transcation, and roll back if necessary.
  • Relatively, call method Update to do update operations. Same thing for inserting, deleting, etc. Just change from xorm.Engine to xorm.Session, methods’ name are the same.
  • Keep in mind that call sess.Rollback before return statement, this is the key for transcation.
  • Finally, call sess.Commit to finish the transcation.

Common functions and methods

Sample code 2

Count records

Use method Count to count how many records in given table:

func getAccountCount() (int64, error) {
	return x.Count(new(Account))
}

It returns all records number because we do not offer any condition. The new(Account) just for reflection, does not indicates any query condition.

Iterative query

Use method Iterate to query all matched records iteratively:

x.Iterate(new(Account), printFn)

Body of function printFn:

var printFn = func(idx int, bean interface{}) error {
	fmt.Printf("%d: %#v\n", idx, bean.(*Account))
	return nil
}

Make it as a function is because sample code will use it multiple times.

The purpose of argument of method Iterate is same as method Count, just for reflection.

Let’s focus on the iterative function declaration: it accepts 2 arguments, the first one is the index of result set(no relation to its ID value); the second one is the empty interface which contains the value, and we need to assert it before using it. In the above example, we know the type is Account, so we use bean.(*Account) to get the actual object we want.

If you think method Iterate isn’t flexible enough, then use the following solution to gain more control of everything:

a := new(Account)
rows, err := x.Rows(a)
if err != nil {
	log.Fatalf("Fail to rows: %v", err)
}
defer rows.Close()

for rows.Next() {
	if err = rows.Scan(a); err != nil {
		log.Fatalf("Fail get row: %v", err)
	}
	fmt.Printf("%#v\n", a)
}

The above example does the exactly same thing as the example of method Iterate. Therefore, use method Iterate can achieve most of simple jobs.

Query specified fields

Use method Cols can specify fields you want to return(or fields that are valuable at the time):

x.Cols("name").Iterate(new(Account), printFn)

In this case, only field Name has value, all the other fields have zero values. Note that method Cols accepts name in the data table, not the field name in the struct.

Omit specified fields

Use method Omit when you want to omit query of some fields:

x.Omit("name").Iterate(new(Account), printFn)

In this case, only field Name has zero value. Same argument rule for method Omit and Cols.

Result offset

Offset query results is very common in paging applications, use method Limit can achieve the same goal:

x.Limit(3, 2).Iterate(new(Account), printFn)

This method accepts at least 1 argument, the first one indicates max number of results; if it has second argument, then means the offset of results. In this case, query results offset 2 and return at most 3 records.

Logging

Generally, use x.ShowSQL = true to enable logging feature of xorm, all SQL statements will be printed to console. If you want to save them into a file, use the following code:

f, err := os.Create("sql.log")
if err != nil {
	log.Fatalf("Fail to create log file: %v\n", err)
	return
}
x.Logger = xorm.NewSimpleLogger(f)

LRU Cache

Xorm is the only ORM that supports LRU cache, it’s very easy to use:

cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000)
x.SetDefaultCacher(cacher)

Now you have the very default LRU cache. For more details like omit or only cache some tables, see documentation.

Event hook

There are 6 kinds of hooks(author is too lazy to add document for it) you can use in xorm. In the sample code, it demonstrates 2, which are BeforeInsert and AfterInsert.

They will be called right before insertion and right after insertion:

func (a *Account) BeforeInsert() {
	log.Printf("before insert: %s", a.Name)
}

func (a *Account) AfterInsert() {
	log.Printf("after insert: %s", a.Name)
}

Run the code and you’ll see the differences.

Summary

Until now, all posts about xorm are finished. It’s true that I didn’t cover everything about xorm, but at least most common ones. Other handy features are better for you to explore during the development of your applications.

Use cases


comments powered by Disqus