DAOs sobre Dapper
La verdad es que los micro-ORMs están de moda (Massive, Dapper, PetaPOCO, SimpleData, etc). Basándome en esta abstracción y en mi querido Gentle.NET, me he decido a construir unos DAOs sobre Dapper, que es usado en Stackoverflow, y como características principales podemos decir: que es fuertemente tipado con una interfaz muy clara, y como extra soporta operaciones asíncronas a DB.
Creo que la mejor manera de entender el funcionamiento es con un ejemplo:
class Example { class Message : BusinessObject<Message> { [PrimaryKey] public Guid Id { get; set; } public string DestinationAddress { get; set; } public string SourceAddress { get; set; } public string UserData { get; set; } public int Ton { get; set; } } public void Example1() { Message m = new Message() { Id = Guid.NewGuid(), DestinationAddress = "34612345678", SourceAddress = "404", UserData = "Example 01", Ton = 1 }; m.Insert(); List<Message> l = Message.FindBy(new SqlCondition("DestinationAddress", Operator.Equals, "34612345678")); m.Remove(); } }
A continuación mostraremos el código de las funciones básicas de CRUD.
public class BusinessObject<T> where T: class { public static SqlConnection GetConnection() { return ConnectionFactory.Create(typeof(T).Namespace); } public static T Retrieve(object id) { string sql = string.Empty; DynamicParameters p = new DynamicParameters(); p.Add(GetPrimaryKey(), id, null, null, null); StringBuilder sb = new StringBuilder() .AppendFormat("select * from {0} where {1} = @{1}", GetTableName(), GetPrimaryKey()); return queryInternal(sb.ToString(), p).FirstOrDefault(); } public void Insert() { string sql = string.Empty; DynamicParameters p = new DynamicParameters(); StringBuilder columns = new StringBuilder(), values = new StringBuilder(); bool first = true; foreach (string prop in GetProperties()) { if (first) { columns.AppendFormat("{0}", prop); values.AppendFormat("@{0}", prop); } else { columns.AppendFormat(", {0}", prop); values.AppendFormat(", @{0}", prop); } p.Add(prop, getPropertyValue(this, prop), null, null, null); first = false; } sql = string.Format("insert into {0} ({1}) values ({2})", GetTableName(), columns.ToString(), values.ToString()); int res = executeInternal(sql, p); } public void Update() { // ... } public void Remove() { // ... } public static List<T> FindBy(SqlCondition[] conditions) { DynamicParameters p = new DynamicParameters(); StringBuilder sb = new StringBuilder() .AppendFormat("select * from {0} where", typeof(T).Name); bool first = true; int i = 0; foreach (SqlCondition c in conditions) { // for multiple conditions with same column string var = c.PropertyName + (i++); if (!first) sb.Append(" AND"); if (c.Value == null) { sb.AppendFormat(" {0} {1} NULL", c.PropertyName, OperatorHelper.ToString(c.Operator)); } else { sb.AppendFormat(" {0} {1} @{2}", c.PropertyName, OperatorHelper.ToString(c.Operator), var); p.Add(var, c.Value, null, null, null); } first = false; } return queryInternal(sb.ToString(), p); }
protected static List<T> queryInternal(string sql, object param) { List<T> l = null; using (var conn = GetConnection()) { try { conn.Open(); l = conn.Query<T>(sql, param, null, false, 0, null).ToList(); } finally { conn.Close(); } } return l; }
Faltaría algo de código para representar las condiciones SQL, así como algunas funciones que usan reflección para optener el nombre de la tabla, propiedades o clave primaria.
Leave a Reply