Blog de Francisco Velázquez

otro blog personal

Posts Tagged ‘DAO

DAOs sobre Dapper

leave a comment »

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.

Advertisements

Written by fravelgue

June 27, 2011 at 8:11 pm

Posted in development

Tagged with , ,

Abstrayendo operaciones básicas en business objects

with one comment

Tras leer el buen artículo de Matt Long, se me ocurrió que tal podría aplicar estos principios para facilitar mi trabajo con Gentle.NET (increíble pero cierto) y tal vez que fuera el origen de un cambio en el motor de persistencia.

Así podríamos tener una clase base para todos nuestros objetos de negocio.


public class BusinessObject<T> : Persistent
        where T : class
    {
        static protected PersistenceBroker persistenceBroker;
        protected Type _type;
        static protected BusinessObject<T> _objToRetrieve = null;
        protected bool _empty = true;
        protected bool _changed = false;

        
        [TableColumn("id", NotNull = true), PrimaryKey(AutoGenerated = false)]
        public int Id { get; set; }

        public bool Changed
        { 
            get { return _changed; } 
        }

        static BusinessObject()
        {
            // TODO Singleton
            if (_objToRetrieve == null) _objToRetrieve = new BusinessObject<T>();
            if (persistenceBroker == null) 
                    persistenceBroker = new PersistenceBroker(typeof(T));
        }

        static public T Retrieve(int id)
        {
            return _objToRetrieve.retrieve(id);         
        }

        protected T retrieve(int id)
        {
            Key key = new Key(typeof(T), true, "Id", id);
            return ((PersistenceBroker)persistenceBroker).RetrieveInstance(typeof(T), key) as T;
        }

        public override void Persist()
        {
            if (Changed || !IsPersisted)
            {
                base.Persist();
                _changed = false;
            }
        }

        public override void Remove()
        {
            base.Remove();            
        }

        // TODO FindBy

        public override bool Equals(object obj)
        {
            bool result = false;
            if (obj != null)
                result = ((this.GetType() == obj.GetType()) 
                    && (((BusinessObject<T>)this).Id == ((BusinessObject<T>)obj).Id));
            return result;
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }
    }

[Serializable]
    [TableName("Example")]
    class Exmple : BusinessObject<Example>
    {
        [TableColumn("name", NotNull = false)]
        public string Name { get; set; }

        [TableColumn("description", NotNull = false)]
        public string Description { get; set; }

        [TableColumn("date", NotNull = false)]
        public DateTime Date { get; set; }

        [TableColumn("error", NotNull = false)]
        public bool Error { get; set; }
    }

Written by fravelgue

December 11, 2010 at 12:41 pm

Posted in .net

Tagged with , , ,

Microsoft y el acceso a datos

with one comment

A través de Ayende, descubro otra nueva forma para realizar el acceso a datos.  Ayende critica no sin razón este nuevo método y parece que no es el único, porque desde microsoft llegan explicaciones, realmente algo positivo que se genere conversación.

Mi opinión es que este es un campo en el que Microsoft no lo ha estado haciendo bien, aunque parecía que iban por buen camino con EF, ahora de nuevo tenemos una nueva tecnología que sólo crea incertimbre.

En aplicaciones empresariales no podemos estar cambiando cada dos años de tecnología de acceso a datos; necesitamos tecnologías que perduren en el tiempo y que sigan manteniéndose y eso es lo que parece que Microsoft no ofrece. Creo que ahora mismo la única opción  es nHibernate, EF ha mejorado mucho situandolo al nivel de nHibernate, pero quién dice que seguirá haciéndolo.

Hay gente que defiende que tener opciones no es malo, de hecho es algo corriente en otras tecnologías, como Java. Pero creo que se debe explicar muy claramente cual es el ámbito de cada una, y no crear confusión con ellas. En este caso parece que va enfocado al desarrollo usando WebMatrix.

Para solucionar todos estos problemas, creo que es fundamental que se actualizen la documentación de p&p Data Guidance. Y por supuesto intentar aceptar soluciones externas sobre todo cuando éstas son mejores que las que se proponen.

Written by fravelgue

August 4, 2010 at 3:19 pm

Posted in development

Tagged with , , ,

Acceso a Datos, NHibernate: Ayende / Romaniello

leave a comment »

Interesante diálogo entre Ayende y Romaniello, del que podemos aprender bastante sobre NHibernate, DAOs y arquitectura de aplicaciones. Muy recomendable tanto el contenido como algunos de sus enlaces.

Written by fravelgue

January 8, 2010 at 2:28 pm

Posted in development

Tagged with , , ,