2012-02-16 11 views
5

Objetivo:exportación a CSV genérico con mesas

Nuestra aplicación está construida usando varios tipos (por ejemplo, persona, PersonSite (ICollection), del sitio - I seleccionado aquellas clases porque tienen una relación). Lo que queremos hacer es poder exportar algunas propiedades del primer tipo (Person) en una tabla excel y luego exportar algunas otras propiedades del segundo tipo (PersonSite) dentro del mismo archivo excel, pero en una nueva tabla en el mismo hoja.

El resultado debe ser similar a esto:

 
_________________ ________________________ ________________ 
|     | |      | |    | 
|PERSON PROPERTIES| | PERSONSITE PROPERTIES | |SITE PROPERTIES | 
|_________________| |________________________| |________________| 
| Name Person 1 | |Relation type for item 1| | Name for item 1| 
|_________________| |________________________| |________________| 
        |Relation type for item 2| | Name for item 2| 
        |________________________| |________________| 
        |Relation type for item 3| | Name for item 3| 
        |________________________| |________________| 
_________________ ________________________ ________________ 
| Name Person 2 | |Relation type for item 1| | Name for item 1| 
|_________________| |________________________| |________________| 
        |Relation type for item 2| | Name for item 1| 
        |________________________| |________________| 

Así, por cada PersonSite que figuran en la lista, nos gustaría crear una tabla que se inserta a continuación de la tabla de la persona.

Así que esto es como mirar la clase Persona (subconjunto de la clase):

public class Person : IObject 
{ 
    public ICollection<PersonSite> PersonSites {get;set;} 
} 

Ahora la clase PersonSite (subconjunto):

public class PersonSite : IObject 
{ 
    public Person Person {get;set;} 
    public Site Site {get;set;} 
    public RelationType RelationType {get;set;} 
} 

La clase del sitio (subconjunto):

public class Site : IObject 
{ 
    public ICollection<PersonSite> PersonSites {get;set;} 
} 

Así que decidimos escribir una clase CSVExporter que utilice expresiones para recuperar las propiedades que deben ser exportado

Este es el esquema que tenemos que poner en práctica lo siguiente:

      
          ____ 
          | |0..* 
______________   __|____|______  1..* _______________ 
| CSV EXPORTER |________| CSV TABLE (T)|__________| CSV COLUMN (T)| 
|______________|  |______________|   |_______________| 
           | 
           |1..* 
         ______|________ 
         | CSV ROWS (T) | 
         |_______________| 

Así que la CSVTable utilizar un tipo genérico que es IObject (tal como se utiliza en las diferentes clases).

Una tabla puede tener varias tablas (por ejemplo, la tabla Person tiene una tabla PersonSite y una tabla PersonSite tiene una tabla Site). Pero el tipo utilizado es diferente ya que navegamos por las diferentes clases (esas clases deben tener una relación).

Al agregar una subtabla a una mesa debemos proporcionar en la expresión que agarrar los objetos del tipo correcto de los elementos principales (persona => Person.PersonSite)

Así que escribió el siguiente fragmento de código para la tabla:

public class CSVExportTable<T> 
    where T : IObject 
{ 

    private Matrix<string> Matrix { get; set; } 
    private ICollection<CSVExportTableColumn<T>> Columns { get; set; } 
    private ICollection<CSVExportTableRow<T>> Rows { get; set; } 
    private ICollection<CSVExportTable<IObject>> SubTables { get; set; } 
    private Expression<Func<T, object>> Link { get; set; } 


    public CSVExportTable() 
    { 
     this.Matrix = new Matrix<string>(); 
     this.Columns = new List<CSVExportTableColumn<T>>(); 
     this.SubTables = new List<CSVExportTable<IObject>>(); 
     this.Rows = new List<CSVExportTableRow<T>>(); 
    } 

    public CSVExportTable<R> AddSubTable<R>(Expression<Func<T, object>> link) where R : IObject 
    { 
     /* This is where we create the link between the main table items and the subtable items (= where we retreive Person => Person.PersonSites as an ICollection<R> since the subtable has a different type (T != R but they have the same interface(IObject))*/ 
    } 

    public void AddColumn(Expression<Func<T, object>> exportProperty) 
    { 
     this.Columns.Add(new CSVExportTableColumn<T>(exportProperty)); 
    } 

    public Matrix<string> GenerateMatrix() 
    { 
     int rowIndex= 0; 
     foreach (CSVExportTableRow<T> row in this.Rows) 
     { 
      int columnIndex = 0; 
      foreach (CSVExportTableColumn<T> column in this.Columns) 
      { 
       this.Matrix = this.Matrix.AddValue(rowIndex, columnIndex, ((string)column.ExportProperty.Compile().DynamicInvoke(row.Item))); 
       columnIndex++; 
      } 
      rowIndex++; 
     } 
     return this.Matrix; 
    } 

    public Matrix<string> ApplyTemplate(ICollection<T> items) 
    { 
     // Generate rows 
     foreach (T item in items) 
     { 
      this.Rows.Add(new CSVExportTableRow<T>(item)); 
     } 
     // Instantiate the matrix 
     Matrix<string> matrix = new Matrix<string>(); 

     // Generate matrix for every row 
     foreach (var row in this.Rows) 
     { 
      matrix = GenerateMatrix(); 
      // Generate matrix for every sub table 
      foreach (var subTable in this.SubTables) 
      { 
       // This it where we should call ApplyTemplate for the current subTable with the elements that the link expression gave us(ICollection). 
      } 
     } 
     return matrix; 
    } 
} 

Y finalmente aquí es la clase CSVExportTableColumn:

public class CSVExportTableColumn<T> where T : IObject 
{ 
    public Expression<Func<T, object>> ExportProperty { get; set; } 

    public CSVExportTableColumn(Expression<Func<T, object>> exportProperty) 
    { 
     this.ExportProperty = exportProperty; 
    } 
} 

alguien ha hecho algo así? ¿O nos dirigimos al camino equivocado? Si este parece ser un buen camino, ¿cómo podemos crear la expresión de enlace (relación) y usarla para recuperar los elementos correctos para usar en la última llamada?

+1

Genial, lo tienes funcionando, ¿puedes cerrarlo? –

+4

Estoy de acuerdo con @MicahArmantrout; Para otros que buscan problemas similares, ¿podría publicar su actualización como una respuesta y aceptarla? También evitará que los que responden intenten resolver su pregunta ... gracias :-) – Jonno

+2

@Whoami publique su solución como respuesta. Puede aceptar esa respuesta (a veces necesita esperar un día o 2 para hacerlo). Rechazará tanto su pregunta como su respuesta si lo hace, ya que ya hizo un excelente trabajo. Ahora el paso final (: –

Respuesta

0

Siento el retraso,

Así que, finalmente, tenemos que trabajar de esta manera:

public Matrix<string> ApplyTemplate(object items) 
    { 
     ICollection<T> castedItems = new List<T>(); 
     // Cast items as a List<T> 
     if (items is List<T>) 
     { 
      castedItems = (ICollection<T>)items; 
     } 
     else if (items is HashSet<T>) 
     { 
      castedItems = ((HashSet<T>)items).ToList(); 
     } 
     // Generate rows 
     foreach (T item in castedItems) 
     { 
      this.Rows.Add(new CSVExportTableRow<T>(item)); 
     } 
     // Instantiate the matrix 
     Matrix<string> matrix = new Matrix<string>(); 

     // Generate matrix for every row 
     foreach (var row in this.Rows) 
     { 
      matrix = GenerateMatrix(); 
      // Generate matrix for every sub table 
      foreach (var subTable in this.SubTables) 
      { 
       matrix = matrix.AddMatrix(subTable.ApplyTemplate(this.Link.Compile().DynamicInvoke(row.Item))); 
      } 
     } 
     return matrix; 
    } 

Esto se aplicará la plantilla para cualquier tabla sub.

Espero que esto pueda ser útil para otros.