miércoles, 18 de septiembre de 2013

Convertir dataReader en un tipo IEnumerable a través de reflexión con c#

En otro post puse un ejemplo de reflexión.
Ahora vamos a ver otro uso de la reflexión, en este caso para convertir un dataReader en un lista genérica, es decir en un tipo IEnumerable<T>

El escenario es útil en los siguientes casos:

  • Trabajamos con LINQ y nos hemos acostumbrado a utilizarlo para tratar las entidades de negocio.
  • Si trabajamos con un ORM (Entity, NHibernate) enlazaremos fácilmente las entidades de negocio y consultas con listas.
  • Pero, si, no trabajamos con un ORM, no lo tendremos tan cómodo.
  • Tampoco si trabajamos con un ORM con enfoque Code First y obtenemos los datos de un procedimiento almacenado.
  • Independientemente de la utilidad del método, queremos ver un ejemplo de método de extensión y/o reflexión.

Paso 1. Crear Método de reflexión.
Recibe por parámetro:
 Un Objeto al que copiar el valor de la propiedad. Observar que es un paso por referencia.
 El nombre/Valor de la propiedad a establecer al objeto.

public class Reflection
{
    public void FillObjectWithProperty(ref object objectTo, string propertyName, object propertyValue)
   {
        Type tOb2 = objectTo.GetType();
         tOb2.GetProperty(propertyName).SetValue(objectTo, propertyValue);
   }
}
Ya tenemos la función. No tiene ningún misterio, utiliza tres métodos básicos de reflexión que hablan por si solos (GetType, GetPropery, y SetValue).

Paso 2. Crear método de extensión.
Es el más complejo, podemos encontrar mucha información en google sobre los métodos de extensión. Pego la función, que está comentada con detalle.
public static class IENumerableExtensions
{
    public static IEnumerable<T> CopyDataReader<T>(this IEnumerable<T> list, DbDataReader dr)
    {
        //Instanciar objecto reflec de la clase Reflection codificada antes
        Reflection reflec = new Reflection();
        //Declarar un objeto "instance" tipo Object y una lista de objetos
        Object instance;
        List<Object> lstObj = new List<Object>();
       
        //Recorrer dataReader
       while (dr.Read()){
            //Crear instancia del objeto necesario. La instancia se crea obteniendo el 
            //tipo de objeto T del objeto list, que es el propio objeto que llama al método de extensión.
            //Es decir se infiere el tipo T y se instancia
            instance= Activator.CreateInstance(list.GetType().GetGenericArguments()[0]);
            
            //Se recorren todos los campos de cada fila del dataReader, y mediante
            //el objeto reflec (método del primer paso) rellenamos el objeto instance con los valores
            //del datareader
        foreach (DataRow drow in dr.GetSchemaTable().Rows){
                    reflec.FillObjectWithProperty(ref instance, drow.ItemArray[0].ToString(), dr[drow.ItemArray[0].ToString()]);
             }
            
            //Añadir objeto instance a la lista
            lstObj.Add(instance);
        }
       
        //Convertir la lista de objetos (lstObj) en la lista List<T> resultante(lstResult)
        List<T> lstResult = new List<T>();
        foreach (Object item in lstObj){
             lstResult.Add((T)Convert.ChangeType(item, typeof(T)));
        }


         return lstResult;
     }
 }


Paso 3. Llamar al método de extensión.
Dado un dataReader (dr)
 var listaTipoT= new List<T>();
 var listaResult = listaTipoT.CopyDataReader(dr).ToList();


Y ya tenemos un List T !!

viernes, 13 de septiembre de 2013

fechas y POO en Javascript

El siguiente ejemplo, trata sobre fechas y Programación orientada a objetos en Javascript.


El ejemplo expuesto, es una clase sencilla con funciones básicas de fecha que se pueden encontrar fácilmente en google, no obstante se exponen en una clase para usarlas cómodamente, y con el objetivo de explicar los conceptos básicos de POO en Javascript, aspecto poco utilizado en este lenguaje.



 
var fech = new classFecha(new Date());
console.log(fech.DiaLargo());

function classFecha(date) {
    var diasSem = new Array("Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado");

    var meses = new Array("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre");


    this.DiaSemana = function () { return diasSem[date.getDay()]; }

    this.Mes = function () { return meses[date.getMonth()]; }

    this.DiaLargo = function () { return this.DiaSemana() + ", " + date.getDate() + " de " + this.Mes() + " de " + date.getFullYear(); }


    this.LunesSemana = function () {
        if (date.getDay() != 0)
            return (date.getDate() + (6 - (7 + (date.getDay() - 2))));
        else
            return (date(date.getDate() - 6));
    };
}

Bien, ahora vamos a comentarlo por partes, que hay mucho que comentar.

 ¿Que es function classFecha? Pués es la definición de una clase en Javascript, estás se definen como funciones.

 Diferencia entre variables definidas como var y this: las definidas como var son campos privados. Las definidas como this son propiedades o métodos públicos.

 Pero, ¿Propiedades o métodos?: Esto es otra cuestión, en general las propiedades, se definen como function, en ese caso siendo puristas son métodos/funciones públicos. Pero se pueden definir como propiedades puras de la siguente forma, por ejemplo:
 DiaSemana: En lugar de, 

this.DiaSemana = function () { return diasSem[date.getDay()]; }

 Codificaríamos,
          this.DiaSemana = (diasSem[date.getDay()]); 

 Y luego la llamaríamos así:  fech.DiaSemana
  En lugar de así: fech.DiaSemana()

 En la mayoría de ejemplos las propiedades son métodos definidas como funciones anónimas, es una costumbre en javascript debido a su sintaxis.


Todavía más cuestiones:

Los más puristas en POO se preguntarán,

¿Y porqué declara métodos de instancia si es una clase sin estados? Cierto, no se están utilizando estados, lo lógico desde un enfoque POO sería definir los métodos como estáticos.
Una razón es para que esté preparada para extenderse añadiéndole propiedades de estado.
Otra razón, y la principal,  es que no me gusta la sintaxis de los métodos estáticos en javascript.

Ese link la explica: http://mistrastadas.blogspot.com.es/2012/01/metodos-estaticos-en-javascript.html


Como podeis ver en el primer link, para definir un método estático hay que sacarlo fuera de la clase y añadirlo con la notación nombreClase.nombreFuncion=(...);  

El segundo link aún tiene otro tema, como añadir propiedades a un objeto en tiempo de ejecución con la clase prototype. No lo vuelvo a explicar pués ya está explicado en el link. En definitiva viene a ser un análogo a los métodos de extensión de C#, pués lo que se consigue así es extender la clase.

viernes, 6 de septiembre de 2013

Reflexión en C# : comparar campos de dos objetos utilizando LINQ


Un ejemplo de reflexión en C# utilizando LINQ. En el caso que se expone se crea la función fieldValuesDiff, que lo que hace es dados dos objetos, que pueden ser de distinto tipo, para todos aquellos campos con el mismo nombre y valor distinto, devuelve un IEnumerable<stObjDif>, es decir una lista de una estructura con el nombre del campo y los dos valores.

En particular yo lo he aplicado para hacer un log de campos modificados. Dados dos entitades de tipo A, le paso por parámetro una instancia de la entidad antes de modificar y otra modificada. Así puedo guardar el log.  

No obstante  se pueden añadir o cambiar fácilmente funciones basadas en esta, por ejemplo la función fieldsValuesEqual, para extraer campos iguales.

public class Reflection
{
    public struct stObjDif
    {
      public string Campo;
      public string ValorObj1;
      public string ValorObj2;
    }

    public List fieldsValuesDiff(object obj1, object obj2)
    {
      Type tOb1 = obj1.GetType();
      Type tOb2 = obj2.GetType();

      var listPropOrig = tOb1.GetProperties().Select(p => p).ToList();
      var listPropMod = tOb2.GetProperties().Select(p => p).ToList();

      return listPropMod.Where(pM =>
              listPropOrig.Count(pO => (pO.Name == pM.Name && pO.GetValue(obj1)!=null && pM.GetValue(obj2)!=null
                              && pO.GetValue(obj1).ToString() != pM.GetValue(obj2).ToString())) == 1
               ).Select(pResult => new stObjDif(){
                     Campo = pResult.Name,
                     ValorObj1 = pResult.GetValue(obj1).ToString(),
                     ValorObj2 = listPropMod.FirstOrDefault(pM => pM.Name == pResult.Name).GetValue(obj2).ToString()
                 }).ToList();
    }