lunes, 11 de agosto de 2014

Dapper, un micro ORM a tener en cuenta

Los ORM (Mapeo objeto – relacional) son una pieza fundamental en el desarrollo de nuestras aplicaciones.
Permite interactuar con la base de datos mediante objetos y listas de objetos, olvidándonos de los tediosos datasets.

Cuando hablamos de ORM nos viene a la cabeza Entity Framework y Nhibernate, pero existen también los llamados micro-orm que son bastante más ligeros y, siendo más simples que los ORM convencionales,  cumplen su función banstante bien, como pueden ser, entre otros, Massive, Simple.Data, Peta Poco y Dapper

Dapper es el ORM en el que se basa Stack Overflow y algunas otras webs.

https://code.google.com/p/dapper-dot-net/

Según los benchmarks en su web, llega a ser bastante más rápido que Entuty Framework y Nhibernate en realizar los Selects.

Dapper se puede usar a partir del Framework 3.5, aunque es recomendable Framework a partir de 4 para usar el potencial de las clases dynamic

Vamos a trastear un poco con él a ver cómo funciona.


Instalación
En primer lugar, decir que se trata de un método extensor de IDbConnection, por lo que podemos utilizar cualquier objeto que implemente IDbConnection( Sql Server, Oracle, MySql, ...)

Podemos descargarlo a través de NuGet, o directamente adjuntando la clase SqlMapper.cs a vuesto proyecto.


Consultas sin objetos mapeados
Para obtener una lista de objetos dinamic sin tener que usar ninguna clase:
            

string connectionString = "Data Source=(localdb)\\v11.0;Initial Catalog=NorthWind;Integrated Security=True";
IDbConnection conn= new SqlConnection(connectionString);
conn.Open();

var empleados = conn.Query("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     Console.WriteLine("{0} {1} - {2}", empleado.FirstName, empleado.LastName, empleado.Country);
conn.Close();
Console.ReadKey();
Nótese que estamos usando Parameters en una clase anónima, por lo que evitamos inyección de SQL.

Consultas sin objetos mapeados en .Net 3.5
Si estuviéramos trabajando con Framework 3.5, bastará con añadir el símbolo de compilación condicional "CSHARP30" en las propiedades del proyecto - Compilar, y obtendremos los valores en IDictionary
var empleados = conn.Query("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     Console.WriteLine("{0} {1} - {2}", empleado["FirstName"], empleado["LastName"], empleado["Country"]);

Consultas con objetos mapeados
Ahora añadimos una clase POCO de Empleados, y veamos que sigue funcionando, esta vez devolviendo un IEnumerable<T>
public class Employees
{
    public int EmployeeId;
    public string LastName;
    public string FirstName;
    public string Country;
}


var empleados = conn.Query<employees>("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     Console.WriteLine("{0} {1} - {2}", empleado.FirstName, empleado.LastName, empleado.Country);
El mapeo que realiza Dapper es la coincidencia del nombre del campo y del nombre de la propiedad de la clase. Si hay alguna propiedad que difiera de los campos de la clase, simplemente no lo mapeará.

Actualizaciones, inserciones y borrados
Para realizar operaciones de escritura usaremos los siguientes ejemplos:

Observa que se pueden ejecutar varias líneas dentro de la sentencia.
conn.Execute(@"set identity_insert employees on;
                insert into employees (EmployeeId, FirstName, LastName, Country) values (@EmployeeId, @FirstName, @LastName, @Country);
                set identity_insert employees off;"
                , new { FirstName = "Oswaldo", EmployeeId = 21, LastName = "Rodriguez", Country = "Cuba" });


conn.Execute("update employees set firstname=@FirstName where employeeId=@EmployeeId", new { FirstName = "Leopoldo", EmployeeId = 21 });

También se pueden realizar operaciones masivas pasando una lista de objetos.
var empleados = conn.Query>empleado<("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     empleado.FirstName = "-" + empleado.FirstName;
conn.Execute("update employees set firstname=@FirstName where employeeId=@EmployeeId", empleados.Select(x=>new {FirstName=x.FirstName, EmployeeId=x.EmployeeId}));

Agregados
var sql="Select * from products p left join categories c on p.CategoryID=c.CategoryID";
var products = conn.Query>Producto, Categoria, Producto<(sql, (prod, cat) => { prod.categoria = cat; return prod; }, splitOn:"CategoryID");
Conclusiones
Como podéis ver, puede ser una buena alternativa para determinados proyectos.
Espero que os sea de utilidad.

No hay comentarios: