Skip to content

Latest commit

 

History

History
303 lines (212 loc) · 9.5 KB

File metadata and controls

303 lines (212 loc) · 9.5 KB

5.5 Desarrollo de un ORM basado en beedb

( El proyecto beedb no es más mantenido, pero el código sigue aun allí )

beedb es un ORM, "Object Relational Mapping", que se desarrolló en Go por mí. Utiliza el estilo de Go para operar con las base de datos, implementando struct para realizar el mapeo de los registros de la base de datos. Es un framework ORM ligero en Go, el propósito de desarrollar este ORM es ayudar a las personas a aprender cómo escribir un ORM, y que encuentre un buen equilibrio entre las funciones y el rendimiento.

beedb es un proyecto de código abierto, y soporta las funciones básicas de un ORM, pero no admite querys asociadas.

Debido a que beedb soporta la interfaz estándar database/sql, cualquier driver compatible con esta interfaz se pueden utilizar en beedb, yo he probado los siguientes drivers:

Mysql: github.com/ziutek/mymysql/godrv

Mysql: code.google.com/p/go-mysql-driver

PostgreSQL: github.com/bmizerany/pq

SQLite: github.com/mattn/go-sqlite3

MS ADODB: github.com/mattn/go-adodb

ODBC: bitbucket.org/miquella/mgodbc

Instalación

Puede usar go get para instalar beedb en su computadora.

go get github.com/astaxie/beedb

Inicialización

En primer lugar, usted tiene que importar todos los paquetes correspondientes de la siguiente manera:

	import (
	    "database/sql"
	    "github.com/astaxie/beedb"
	    _ "github.com/ziutek/mymysql/godrv"
	)

Luego hay que abrir una conexión de base de datos y crear un objeto beedb (en este ejemplo MySQL):

	db, err := sql.Open("mymysql", "test/xiemengjun/123456")
	if err != nil {
	    panic(err)
	}
	orm := beedb.New(db)

beedb.New() en realidad tiene dos argumentos, el primero es para el requisito estándar, y el segundo es para indicar el motor de base de datos, pero si usted está utilizando MySQL/SQLite, puede saltarse el segundo.

De otra forma, usted tendrá que inicializarlo, como con SQLServer:

	orm = beedb.New(db, "mssql")

PostgreSQL:

	orm = beedb.New(db, "pg")

beedb soporta depuración, para permitirlo use el siguiente código:

	beedb.OnDebug=true

Ahora tenemos un struct para la tabla de la base de datos Userinfo que hemos utilizado en las secciones anteriores.

	type Userinfo struct {
	    Uid     int `PK` // si la clave principal no es id, es necesario agregar el tag `PK` para su clave primaria personalizada.
	    Username    string
	    Departname  string
	    Created     time.Time
	}

Tenga en cuenta que beedb auto-convert usa su estilo camel para nombrar las tablas y campos con guiones bajos y letras minúsculas. Por ejemplo, tenemos UserInfo como el nombre del struct, y será user_info en la base de datos, la misma regla para los nombres de campos.

Isertar datos

El siguiente ejemplo muestra cómo utilizar beedb para salvar el struct en lugar de comandos SQL y utilizar el método Save para aplicar el cambio.

	var saveone Userinfo
	saveone.Username = "Test Add User"
	saveone.Departname = "Test Add Departname"
	saveone.Created = time.Now()
	orm.Save(&saveone)

Y puede comprobar saveone.Uid después de haberlo insertado, su valor de ID es auto incremental, el método Save hizo este trabajo por usted.

beedb proporciona otra forma de insertar los datos, que es utilizando map.

	add := make(map[string]interface{})
	add["username"] = "astaxie"
	add["departname"] = "cloud develop"
	add["created"] = "2012-12-02"
	orm.SetTable("userinfo").Insert(add)

Insertar datos múltiples:

	addslice := make([]map[string]interface{}, 10)
	add:=make(map[string]interface{})
	add2:=make(map[string]interface{})
	add["username"] = "astaxie"
	add["departname"] = "cloud develop"
	add["created"] = "2012-12-02"
	add2["username"] = "astaxie2"
	add2["departname"] = "cloud develop2"
	add2["created"] = "2012-12-02"
	addslice =append(addslice, add, add2)
	orm.SetTable("userinfo").InsertBatch(addslice)

La forma que te mostré arriba es como una chain query, debe estar familiarizado si sabe de jQuery. Este devuelve el objeto ORM original después de las llamadas y sigue haciendo otros trabajos.

El metodo SetTable le dice al ORM que queremos insertar los datos de la tabla userinfo.

Actualización de datos

Siga el ejemplo anterior, para ver cómo actualizar los datos. Ahora tenemos el valor de clave principal de saveone(UID), por lo que beedb ejecuta la operación de actualización en lugar de insertar nuevo registro.

	saveone.Username = "Update Username"
	saveone.Departname = "Update Departname"
	saveone.Created = time.Now()
	orm.Save(&saveone)  // update

Usted también puede utilizar map para la actualización de datos:

	t := make(map[string]interface{})
	t["username"] = "astaxie"
	orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)

Voy a explicar algunos de los métodos que hemos utilizado anteriormente:

  • .SetPK() le dice al ORM que uid es la clave principal de la tabla userinfo.
  • .Where() establece las condiciones, soporta múltiples argumentos, si el primer argumento es un número entero, una forma corta de Where("<primary key>=?", <value>).
  • .Update() este método acepta map y actualiza la base de datos.

Consultar datos

La interfaz de consulta de beedb es muy flexible, veamos algunos ejemplos:

Ejemplo 1, consulta por clave principal:

	var user Userinfo
	// Where acepta dos argumentos, suporta enteros
	orm.Where("uid=?", 27).Find(&user)

Ejemplo 2:

	var user2 Userinfo
	orm.Where(3).Find(&user2) // forma corta que omite la clave primaria

Ejemplo 3, otras condiciones en la consulta:

	var user3 Userinfo
	// Where acepta dos argumentos, soporta el tipo char.
	orm.Where("name = ?", "john").Find(&user3)

Ejemplo 4, condiciones más complejas:

	var user4 Userinfo
	// Where acepta tres argumentos
	orm.Where("name = ? and age < ?", "john", 88).Find(&user4)

Ejemplos para conseguir varios registros:

Ejemplo 1, recibe 10 registros donde id> 3 y se inicia con la posición 20:

	var allusers []Userinfo
	err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers)

Ejemplo 2, omite el segundo argumento del límite, por lo que empieza con 0 y recibe 10 registros:

	var tenusers []Userinfo
	err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers)

Ejemplo 3, consigue todos los registros:

	var everyone []Userinfo
	err := orm.OrderBy("uid desc,username asc").FindAll(&everyone)

Como puede ver, el método límite es para limitar el número de resultados.

  • .Limit() admite dos argumentos, que son el número de resultados y la posición de inicio. 0 es el valor predeterminado de la posición de inicio.
  • .OrderBy() es para ordenar los resultados, los argumentos son la condición del orden.

Todos los ejemplos que se ven son mapeados a struct y también se puede simplemente poner los datos en un map de la siguiente manera:

	a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap()
  • .Select() le dice a beedb cuántos campos desea obtener de la tabla de base de datos, devuelve todos los campos por defecto.
  • .FindMap() devuelve el tipo []map[string][]byte, entonces necesita convertirlos a otros tipos por usted mismo.

Eliminar datos

beedb proporciona muchos métodos para eliminar datos.

Ejemplo 1, eliminar un solo registro:

	// saveone es uno de los ejemplos anteriores.
	orm.Delete(&saveone)

Ejemplo 2, eliminar varios registros:

	// alluser es una lista que contiene multiples registros
	orm.DeleteAll(&alluser)

Ejemplo 3, eliminar registros mediante SQL:

	orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()

Consultas asociada

beedb no soporta join entre struct. Sin embargo, ya que algunas aplicaciones necesitan esta característica, aquí hay una implementacion:

	a, _ := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid")
		.Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap()

Vemos un nuevo método llamado .Join(), tiene tres argumentos:

  • El primer argumento: Tipo of Join; INNER, LEFT, OUTER, CROSS, etc.
  • El segundo argumento: la tabla con la que desea que se una.
  • El tercer argumento: la condición para el join.

Group By y Having

beedb también tiene una implementacion de group by y having.

	a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
  • .GroupBy() indica el campo por el que se va a agrupar.
  • .Having() indica la condición del having.

Futuro

He recibido muchos comentarios de muchas personas de todo el mundo, y estoy pensando en la reconfiguración en los siguientes aspectos:

  • Implementar un diseño de interfaz como database/sql/driver con el fin de implementar las operaciones CRUD correspondientes.
  • Implementar el diseño de base de datos relacional, uno a uno, uno a muchos, muchos a muchos, aquí están algunas muestras:
				type Profile struct {
					Nickname string
					Mobile   string
				}
				type Userinfo struct {
					Uid         int
					PK_Username string
					Departname  string
					Created     time.Time
					Profile     HasOne
				}	
  • Auto-crear tablas e índices.
  • Implementar pool de conexiones a través goroutine.

Enlaces