Pregunta

Dada una lista de objetos, estoy necesitando para transformarlo en un conjunto de datos, donde cada elemento de la lista es representada por una fila y cada propiedad es una columna de la fila. Este conjunto de datos a continuación, se pasa a un función Aspose.Cells con el fin de crear un documento de Excel como un informe.

Decir que tengo lo siguiente:

public class Record
{
   public int ID { get; set; }
   public bool Status { get; set; }
   public string Message { get; set; }
}

Dada una lista de registros, ¿cómo transformarlo en un conjunto de datos de la siguiente manera:

ID Status Message
1  true   "message" 
2  false  "message2" 
3  true   "message3" 
...

Por el momento lo único que se me ocurre es la siguiente:

DataSet ds = new DataSet
ds.Tables.Add();
ds.Tables[0].Add("ID", typeof(int));    
ds.Tables[0].Add("Status", typeof(bool));
ds.Tables[0].Add("Message", typeof(string));

foreach(Record record in records)
{
    ds.Tables[0].Rows.Add(record.ID, record.Status, record.Message);
}

Pero de esta manera me deja pensando que debe haber una mejor manera ya que por lo menos si se añaden nuevos inmuebles al Registro entonces no van a aparecer en el conjunto de datos ... pero, al mismo tiempo que me permite controlar el orden de cada alojamiento se añade a la fila.

¿Alguien sabe de una mejor manera de hacer esto?

¿Fue útil?

Solución

Puede hacerlo a través de la reflexión y los genéricos, la inspección de las propiedades del tipo subyacente.

Tenga en cuenta que este método de extensión que yo uso:

    public static DataTable ToDataTable<T>(this IEnumerable<T> collection)
    {
        DataTable dt = new DataTable("DataTable");
        Type t = typeof(T);
        PropertyInfo[] pia = t.GetProperties();

        //Inspect the properties and create the columns in the DataTable
        foreach (PropertyInfo pi in pia)
        {
            Type ColumnType = pi.PropertyType;
            if ((ColumnType.IsGenericType))
            {
                ColumnType = ColumnType.GetGenericArguments()[0];
            }
            dt.Columns.Add(pi.Name, ColumnType);
        }

        //Populate the data table
        foreach (T item in collection)
        {
            DataRow dr = dt.NewRow();
            dr.BeginEdit();
            foreach (PropertyInfo pi in pia)
            {
                if (pi.GetValue(item, null) != null)
                {
                    dr[pi.Name] = pi.GetValue(item, null);
                }
            }
            dr.EndEdit();
            dt.Rows.Add(dr);
        }
        return dt;
    }

Otros consejos

Además de la utilización adicional Reflection para determinar las propiedades de Record clase para cuidar de la adición de nuevas propiedades, que es más o menos la misma.

He encontrado este código en foro de Microsoft. Esto es hasta ahora uno de manera más sencilla, fácil de entender y utilizar. Esto me ha ahorrado horas. He personalizado esto como método de extensión sin ningún cambio en implementaion real. A continuación se muestra el código. que no requiere mucha explicación.

Se pueden utilizar dos firma de la función con la misma aplicación

1) público ToDataSetFromObject conjunto de datos estática (esto objeto dsCollection)

2) de datos pública ToDataSetFromArrayOfObject estática (esto objeto [] arrCollection). Voy a usar éste por debajo de ejemplo.

// <summary>
// Serialize Object to XML and then read it into a DataSet:
// </summary>
// <param name="arrCollection">Array of object</param>
// <returns>dataset</returns>

public static DataSet ToDataSetFromArrayOfObject( this object[] arrCollection)
{
    DataSet ds = new DataSet();
    try {
        XmlSerializer serializer = new XmlSerializer(arrCollection.GetType);
        System.IO.StringWriter sw = new System.IO.StringWriter();
        serializer.Serialize(sw, dsCollection);
        System.IO.StringReader reader = new System.IO.StringReader(sw.ToString());
        ds.ReadXml(reader);
    } catch (Exception ex) {
        throw (new Exception("Error While Converting Array of Object to Dataset."));
    }
    return ds;
}

Para utilizar esta extensión en el código

Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
    dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}

He escrito una pequeña biblioteca a mí mismo para realizar esta tarea. Se utiliza la reflexión solamente por primera vez un tipo de objeto debe ser traducida a una tabla de datos. Emite un método que hacer todo el trabajo la traducción de un tipo de objeto.

Su rápida ardiente. Lo puedes encontrar aquí: ModelShredder en GoogleCode

I hecho algunos cambios en el método de extensión de CMS para manejar el caso cuando el List contiene elementos primitivos o String. En ese caso el DataTable resultante sólo tendrá una Column con un Row para cada uno de los valores en la lista.

Al principio pensé de incluir todos los tipos de valor (no sólo los tipos primitivos), pero yo no quería Estructuras (que son tipos de valor) que se incluirán.

Este cambio surgió de mi necesidad de convertir un List(Of Long) o List<long>, en un DataTable utilizarlo como un parámetro con valores de tabla en un MS SQL 2008 procedimiento almacenado.

Lo siento mi es el código de VB a pesar de que esta pregunta se etiqueta ; mi proyecto es en VB (no es mi elección) y que no debería ser difícil de aplicar los cambios en C #.

Imports System.Runtime.CompilerServices
Imports System.Reflection

Module Extensions

    <Extension()>
    Public Function ToDataTable(Of T)(ByVal collection As IEnumerable(Of T)) As DataTable
        Dim dt As DataTable = New DataTable("DataTable")
        Dim type As Type = GetType(T)
        Dim pia() As PropertyInfo = type.GetProperties()

        ' For a collection of primitive types create a 1 column DataTable
        If type.IsPrimitive OrElse type.Equals(GetType(String)) Then
            dt.Columns.Add("Column", type)
        Else
            ' Inspect the properties and create the column in the DataTable
            For Each pi As PropertyInfo In pia
                Dim ColumnType As Type = pi.PropertyType
                If ColumnType.IsGenericType Then
                    ColumnType = ColumnType.GetGenericArguments()(0)
                End If
                dt.Columns.Add(pi.Name, ColumnType)
            Next

        End If

        ' Populate the data table
        For Each item As T In collection
            Dim dr As DataRow = dt.NewRow()
            dr.BeginEdit()
            ' Set item as the value for the lone column on each row
            If type.IsPrimitive OrElse type.Equals(GetType(String)) Then
                dr("Column") = item
            Else
                For Each pi As PropertyInfo In pia
                    If pi.GetValue(item, Nothing) <> Nothing Then
                        dr(pi.Name) = pi.GetValue(item, Nothing)
                    End If
                Next
            End If
            dr.EndEdit()
            dt.Rows.Add(dr)
        Next
        Return dt
    End Function

End Module
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top