none
Crear Clase Generica para Convertir Lista<T> a DataSet (Enviando parametros para nombres de columnas. etc)

    Question

  • tengo un consulta en particular respecto a este tema:  Estoy trabajando en una aplicacion con servicios WCF cuyo tipo de retorno de datos es List<T> usando el Entity Framework 4.  El Mapeo de la aplicacion es por decirlo menos gigante.

     

    Entonces al momento de traerme datos para pasarlos a un grid o algo mas, los metodos definidos en los servicios me traen demasiados datos y al devolver Listas con TIPO (Entidades del Mapeo = Tablas de la Base) tengo que traerme todos los atributos aunque no los necesite. Y toma mucho tiempo asignar en runtime datos a un grid y ocultar columnas etc...

    Por esta razon,  me desarrolle una pequeña clase para convertir de List<T> al Dataset que yo necesite. Pero quiero hacerla generica una especie de esto:

     

    public DataSet convertir Lista(Lista<'cualquier tipo'> listaTipada, Object[] obj )

    {


    }

     

    Donde el object[] obj sera bidimensional contendra los nombres de las columnas de mi datatable, con su tipo de dato correspondiente (que seran los mismos de mi lista, obviamente eso lo sabe el desarrollador) y simplemente ser pasado como parametro para sacar un DataSet de una Lista<T> 'filtrada' unicamente por las columnas que deseo.

    Obviamente se que lo mejor es hacer las consultas mas especificas, pero recien estoy entrando en este proyecto y los Servicios estan diseñados asi, y por el momento debo trabajar asi. Estos servicios y las consultas han sido desarrollados por chicos sin mucha experiencia en Linq, entonces me encuentro con esto que me vuelve loco cada vez que quiero probar los cambios en mi aplicacion.

     

    Esta es el metodo que deseo hacer generico. aqui lo hice a la medida de mi necesidad. 

     

     

    public DataSet ConvertirLista(List<UnidadAcademica> lista)
     {
      DataSet dsResult = new DataSet();
      DataTable dt = new DataTable(); 
    
      //Creo un DataTable solo con las propiedades que quiero
      dt.Columns.Add("Id", typeof(Int32));
      dt.Columns.Add("Nombre", typeof(string));
    
      foreach(UnidadAcademica uni in lista ) 
      { 
      DataRow row = dt.NewRow(); 
      // realizo las asignaciones correspondientes
      row["Id"] = uni.Id;
      row["Nombre"] = uni.Nombre;  
      dt.Rows.Add(row); 
      } 
       
      dsResult.Tables.Add(dt);
      return dsResult;
     }
    

    Friday, January 28, 2011 3:43 PM

Answers

  • hola

    claro el tema es que aqui se devuelve un datatable sin tipo, ya que los nombres de las columnas los tomara de las propiedades de DocumentoResult

    es tal como lo comentas

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Friday, January 28, 2011 4:53 PM
  • ademas de la propuesta de Leandro, tambien lo puedes hacer con tu idea original usando Reflection, ejemplo:

        private DataSet CrearDataSet<T>(IList<T> lista) where T : class, new()
        {
          DataSet ds = new DataSet();
          DataTable table = new DataTable();
    
          // crear nueva tabla
          T entidad = new T();
          PropertyInfo[] pInfo = entidad.GetType().GetProperties();
          foreach (PropertyInfo prop in pInfo)
          {
            object[] ca = prop.GetCustomAttributes(true);
            if (ca.Length == 0) continue;
            if (ca[0] is DataMemberAttribute)
            {
              table.Columns.Add(new DataColumn(prop.Name, Type.GetType(prop.PropertyType.FullName)));
            }
          }
    
          if (table.Columns.Count > 0)
          {
            // llenar tabla
            foreach (T t in lista)
            {
              pInfo = t.GetType().GetProperties();
              DataRow row = table.NewRow();
              foreach (PropertyInfo prop in pInfo)
              {
                object[] ca = prop.GetCustomAttributes(true);
                if (ca.Length == 0) continue;
                if (ca[0] is DataMemberAttribute)
                {
                  row[prop.Name] = prop.GetValue(t, null).ToString();
                }
              }
              table.Rows.Add(row);
            }
          }
    
          ds.Tables.Add(table);
          return ds;
        }
    
    

    y para usarlo seria:

    DataSet ds = CrearDataSet<ServiceReference1.Datos>(datos);
    
    
    Salu2,


    Marvin E. Pineda

    Marvin's Blog
    San Pedro Sula
    Honduras. C.A.


    Aún el necio cuando calla, es contado por sabio.
    Friday, January 28, 2011 7:38 PM
  • hola

    revisa este articulo

    Linq DataSet – Agrupar y totalizar

    si puede suar metodo de extension, por ahio aplicar CopyToDataTable() seria muy util

    veras que de una lista obtienes el datatable

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Friday, January 28, 2011 4:20 PM

All replies

  • Lo que buscas es:

    public DataSet convertir Lista<T>(Lista<T> listaTipada, Object[] obj )

    Pero el problema es que tu asignas un Id y un Nombre, y T no tienen ni Id ni Nombre :S Para poder hacer eso necesitarías que cualquier cosa que sea T implemente cierta interfaz o herede de alguna clase en concreto que tenga esas propiedades y métodos comunes a todos los T.

    Un saludo



    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games

    Friday, January 28, 2011 3:58 PM
  • hola

    revisa este articulo

    Linq DataSet – Agrupar y totalizar

    si puede suar metodo de extension, por ahio aplicar CopyToDataTable() seria muy util

    veras que de una lista obtienes el datatable

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Friday, January 28, 2011 4:20 PM
  •  

     

    Gracias Leandro

    Estuve analizando el post en tu blog y tengo una pequeña consulta que hacerte sobre el mismo:

    private void button1_Click(object sender, EventArgs e)
    {

        var query = from item in Datos().AsEnumerable()
                    group item by item["Documento"].ToString() into g
                    select new DocumentoResult
                    {
                        Documento = g.Key,
                        CantRegistros = g.Count(),
                        Total = g.Sum(x => Convert.ToInt32(x["Total"]))
                    };


        DataTable resultado = query.CopyToDataTable<DocumentoResult>();

        dataGridView1.AutoGenerateColumns = true;
        dataGridView1.DataSource = resultado;

    }
    DocumentoResult vendria formar un nuevo Tipo..??? Y mi DataTable vendria a ser de tipo DocumentoResult y todo lo que esta entre
    las llaves del Select new vendrian a ser los atributos de mi DataTable..?? Es asi la descripcion del codigo. Si es asi hare pruebas 
    y les contaré. 



    Atentamente. Eduardo Pérez Leyton
    Friday, January 28, 2011 4:33 PM
  • hola

    claro el tema es que aqui se devuelve un datatable sin tipo, ya que los nombres de las columnas los tomara de las propiedades de DocumentoResult

    es tal como lo comentas

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Friday, January 28, 2011 4:53 PM
  • Gracias Leandro y Vicente...

    Hare pruebas en mi aplicacion a ver como me resulta esto.


    Atentamente. Eduardo Pérez Leyton
    Friday, January 28, 2011 7:37 PM
  • ademas de la propuesta de Leandro, tambien lo puedes hacer con tu idea original usando Reflection, ejemplo:

        private DataSet CrearDataSet<T>(IList<T> lista) where T : class, new()
        {
          DataSet ds = new DataSet();
          DataTable table = new DataTable();
    
          // crear nueva tabla
          T entidad = new T();
          PropertyInfo[] pInfo = entidad.GetType().GetProperties();
          foreach (PropertyInfo prop in pInfo)
          {
            object[] ca = prop.GetCustomAttributes(true);
            if (ca.Length == 0) continue;
            if (ca[0] is DataMemberAttribute)
            {
              table.Columns.Add(new DataColumn(prop.Name, Type.GetType(prop.PropertyType.FullName)));
            }
          }
    
          if (table.Columns.Count > 0)
          {
            // llenar tabla
            foreach (T t in lista)
            {
              pInfo = t.GetType().GetProperties();
              DataRow row = table.NewRow();
              foreach (PropertyInfo prop in pInfo)
              {
                object[] ca = prop.GetCustomAttributes(true);
                if (ca.Length == 0) continue;
                if (ca[0] is DataMemberAttribute)
                {
                  row[prop.Name] = prop.GetValue(t, null).ToString();
                }
              }
              table.Rows.Add(row);
            }
          }
    
          ds.Tables.Add(table);
          return ds;
        }
    
    

    y para usarlo seria:

    DataSet ds = CrearDataSet<ServiceReference1.Datos>(datos);
    
    
    Salu2,


    Marvin E. Pineda

    Marvin's Blog
    San Pedro Sula
    Honduras. C.A.


    Aún el necio cuando calla, es contado por sabio.
    Friday, January 28, 2011 7:38 PM
  •  

     

    Excelente Marvin, me parece muy interesante tu enfoque.  Intentare probarlo a ver si funciona para lo que yo deseo hacer. En todo caso lo explicare mas detallado:

    1.- Tengo un Lista<UnidadAcademica> que la quiero convertir en un sencillo DataSet

    Condiciones: En mi DataSet no deseo almacenar todos los atributos que posee Lista<UnidadAcademica> sino solo algunos. ¿Como me lo imagino? Pues asi (pseudocodigo):

    public void CrearDataset(List<CUALQUIER TIPO> LstUnidades, object[n,n] campos)

    {

    }

    Donde, en el arreglo campos yo como desarrollador ingresaré los datos de esta manera antes de enviarlo como parametro:

    campos[0,0] ='Nombre de Campo1'; campos[0,1]=TipodeDatoCampo1  <Obviamente el nombre completo del tipo. 'System. etc..'>

    campos[1,0] ='Nombre de Campo1'; campos[1,1]=TipodeDatoCampo2

    Y asi sucesivamente, obviamente el nombre de los campos debera coincidir contra el nombre atributos de mi Lista<CUALQUIERTIPO> para poder hacer la asignacion.

    Mas o menos esa es la idea, ya que como dije anteriormente mis servicios me devuelven todos List<> y necesito en DataSets esa info.

    Probare tu codigo a ver si con modificaciones me sirve o asi como esta, en todo caso muchas gracias a todos por la colaboracion.

     

          


    Atentamente. Eduardo Pérez Leyton
    Friday, January 28, 2011 8:10 PM
  • entiendo, segun el metodo que te plantie, seria mejor pasar la lista de columnas que no quieres que se agreguen a la tabla así esta lista seria un string[] con los nombres sin necesidad de especificar el tipo, creo que te funcionaria mejor y seria más simple y menos engorrosa.

    Salu2,


    Marvin E. Pineda

    Marvin's Blog
    San Pedro Sula
    Honduras. C.A.


    Aún el necio cuando calla, es contado por sabio.
    Friday, January 28, 2011 8:19 PM