2009-08-07 21 views
15

Tengo una lista genérica de objetos. Cada objeto tiene 9 propiedades de cadena. Quiero convertir esa lista en un conjunto de datos que pueda pasar a una vista de tabla de datos ... ¿Cuál es la mejor manera de hacerlo?Convertir lista genérica a conjunto de datos en C#

+1

posible duplicado de [¿Cómo transformar una lista en un conjunto de datos?] (Http://stackoverflow.com/questions/523153/how- do-i-transform-a-listt-into-a-dataset) –

Respuesta

12

¿Ha intentado enlazar la lista directamente a la vista de tabla de datos? Si no, intente eso primero porque le ahorrará mucho dolor. Si ya lo ha intentado, díganos qué salió mal para que podamos aconsejarle mejor. El enlace de datos le proporciona un comportamiento diferente según las interfaces que implemente su objeto de datos. Por ejemplo, si su objeto de datos solo implementa IEnumerable (por ejemplo, List), obtendrá un enlace unidireccional muy básico, pero si también implementa IBindingList (por ejemplo, BindingList, DataView), obtendrá enlace bidireccional.

+0

vinculante directamente no funcionará muy a menudo: es lento, y la clasificación es un dolor. Si solo alcanza 1000 puntos, está bien, para todo lo demás, recomiendo un traductor rápido de dataTable como mi ModelShredder (ver a continuación) –

+1

La clasificación es un problema. También lo está filtrando. Lo mismo ocurre con la edición. Es posible construir un objeto que admita todos los casos de uso que DataTable hace, pero no es una cantidad de trabajo trivial, especialmente si se compara con simplemente copiar los datos en una DataTable. –

+0

yup, es por eso que he escrito modelshredder. Me temo que la edición, por supuesto, no es compatible, pero no veo esto como un problema porque creo que la edición de datos en una tabla debe evitarse por las razones mencionadas anteriormente. Siempre hay excel :-) –

0

Una opción sería utilizar un System.ComponenetModel.BindingList en lugar de una lista.

Esto le permite usarlo directamente dentro de un DataGridView. Y a diferencia de un System.Collections.Generic.List normal actualiza el DataGridView en los cambios.

2

código de la fuerza bruta para responder a su pregunta:

DataTable dt = new DataTable(); 

//for each of your properties 
dt.Columns.Add("PropertyOne", typeof(string)); 

foreach(Entity entity in entities) 
{ 
    DataRow row = dt.NewRow(); 

    //foreach of your properties 
    row["PropertyOne"] = entity.PropertyOne; 

    dt.Rows.Add(row); 
} 

DataSet ds = new DataSet(); 
ds.Tables.Add(dt); 
return ds; 

Ahora la pregunta real. Por qué querrías hacer esto? Como se mencionó anteriormente, puede vincular directamente a una lista de objetos. ¿Tal vez una herramienta de informes que solo toma conjuntos de datos?

+0

Una respuesta a por qué uno quiere hacer esto, de todos modos, es WCF. Los servicios realmente no les gusta poner los genéricos en el cable. Estoy escribiendo un código para devolver los resultados paginados y ordenados de un repositorio y estoy lidiando con un DataSet por ahora ... Una razón es que los campos devueltos no son siempre los mismos ... No estoy seguro si eso volará, podría necesitar DTO, lo que significa que tengo otros problemas, pero estoy divagando :-) –

2

He escrito una pequeña biblioteca para realizar esta tarea. Utiliza la reflexión solo la primera vez que se traduce un tipo de objeto a una tabla de datos. Emite un método que hará todo el trabajo traduciendo un tipo de objeto.

Es la solución más rápida que conozco (es por eso que la desarrollé :-)). Puede encontrarlo aquí: ModelShredder en GoogleCode

Actualmente, solo admite la traducción a una DataTable. Al formular su pregunta, esto debería ser suficiente. Soporte para DataSets (piense en un ORM reverso simple) ya está desarrollado, se lanzará en dos versiones cuando regrese de vacaciones :-)

4

Puede crear un método de extensión para agregar todos los valores de propiedad a través de la reflexión:

public static DataSet ToDataSet<T>(this IList<T> list) 
{ 
    Type elementType = typeof(T); 
    DataSet ds = new DataSet(); 
    DataTable t = new DataTable(); 
    ds.Tables.Add(t); 

    //add a column to table for each public property on T 
    foreach(var propInfo in elementType.GetProperties()) 
    { 
     t.Columns.Add(propInfo.Name, propInfo.PropertyType); 
    } 

    //go through each property on T and add each value to the table 
    foreach(T item in list) 
    { 
     DataRow row = t.NewRow(); 
     foreach(var propInfo in elementType.GetProperties()) 
     { 
      row[propInfo.Name] = propInfo.GetValue(item, null); 
     } 
    } 

    return ds; 
} 
+0

Gracias por el código, un pequeño problema sin embargo, los tipos de Nullable son bombardeo ... Voy a intentar modificarlo para acomodarlos, pero yo no soy un profesional de la reflexión. Si obtengo algo resuelto, publicaré una actualización :-) –

+0

Ok, tuve que hacer dos cambios, uno para los tipos Nullable y otro para los valores nulos ... t.columnas.Add (propInfo.Name, propInfo.PropertyType); se convierte en Tipo ColType = Nullable.GetUnderlyingType (propInfo.PropertyType) ?? propInfo.PropertyType; t.columnas.Add (propInfo.Name, ColType); y fila [propInfo.Name] = propInfo.GetValue (elemento, nulo); se convierte en fila [propInfo.Name] = propInfo.GetValue (elemento, nulo) ?? DBNull.Value; Gracias por el código :-) –

11

Hay un error con el código de extensión de Lee anterior, necesita agregar la fila recién llena a la tabla t cuando itere a través de los elementos de la lista.

public static DataSet ToDataSet<T>(this IList<T> list) { 

Type elementType = typeof(T); 
DataSet ds = new DataSet(); 
DataTable t = new DataTable(); 
ds.Tables.Add(t); 

//add a column to table for each public property on T 
foreach(var propInfo in elementType.GetProperties()) 
{ 
    t.Columns.Add(propInfo.Name, propInfo.PropertyType); 
} 

//go through each property on T and add each value to the table 
foreach(T item in list) 
{ 
    DataRow row = t.NewRow(); 
    foreach(var propInfo in elementType.GetProperties()) 
    { 
      row[propInfo.Name] = propInfo.GetValue(item, null); 
    } 

    //This line was missing: 
    t.Rows.Add(row); 
} 


return ds; 

}

55

Me disculpo por poner una respuesta a esta pregunta, pero pensé que sería la forma más fácil de ver mi código final. Incluye correcciones para tipos anulables y valores nulos :-)

public static DataSet ToDataSet<T>(this IList<T> list) 
    { 
     Type elementType = typeof(T); 
     DataSet ds = new DataSet(); 
     DataTable t = new DataTable(); 
     ds.Tables.Add(t); 

     //add a column to table for each public property on T 
     foreach (var propInfo in elementType.GetProperties()) 
     { 
      Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; 

      t.Columns.Add(propInfo.Name, ColType); 
     } 

     //go through each property on T and add each value to the table 
     foreach (T item in list) 
     { 
      DataRow row = t.NewRow(); 

      foreach (var propInfo in elementType.GetProperties()) 
      { 
       row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value; 
      } 

      t.Rows.Add(row); 
     } 

     return ds; 
    } 
+2

¡Estupendo! ¡Esto me acaba de salvar la vida en un proyecto que estoy haciendo ahora mismo! – Konamiman

+1

Acabo de ahorrarme algo de tiempo. Gracias – Willem

+2

Gracias por esto, gran fragmento :) Solo una corrección de errores, agregué if (list.Count()!= 0) antes de foreach, porque, si la lista que desea convertir está vacía, el código arrojará una excepción. –

1

He modificado ligeramente la respuesta aceptada manejando los tipos de valores. Me encontré con esto cuando trato de hacer lo siguiente y porque GetProperties() es de longitud cero para los tipos de valor. Obtuve un conjunto de datos vacío.Sé que este no es el caso de uso para el OP, pero pensé que publicaría este cambio en caso de que alguien más se topara con lo mismo.

Enumerable.Range(1, 10).ToList().ToDataSet(); 

public static DataSet ToDataSet<T>(this IList<T> list) 
{ 
    var elementType = typeof(T); 
    var ds = new DataSet(); 
    var t = new DataTable(); 
    ds.Tables.Add(t); 

    if (elementType.IsValueType) 
    { 
     var colType = Nullable.GetUnderlyingType(elementType) ?? elementType; 
     t.Columns.Add(elementType.Name, colType); 

    } else 
    { 
     //add a column to table for each public property on T 
     foreach (var propInfo in elementType.GetProperties()) 
     { 
      var colType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; 
      t.Columns.Add(propInfo.Name, colType); 
     } 
    } 

    //go through each property on T and add each value to the table 
    foreach (var item in list) 
    { 
     var row = t.NewRow(); 

     if (elementType.IsValueType) 
     { 
      row[elementType.Name] = item; 
     } 
     else 
     { 
      foreach (var propInfo in elementType.GetProperties()) 
      { 
       row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value; 
      } 
     } 
     t.Rows.Add(row); 
    } 

    return ds; 
} 
0

me encontré con este código en el foro Microsoft. Hasta ahora, esta es una de las formas más sencillas, fáciles de entender y usar. Esto me ha ahorrado horas, lo he personalizado como método de extensión sin ningún cambio en el método real. A continuación está el código. no requiere mucha explicación.

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

1) ToDataSetFromObject conjunto de datos estáticos públicos (este objeto dsCollection)

2) ToDataSetFromArrayOfObject conjunto de datos estáticos públicos (este objeto [] arrCollection). Voy a usar este por 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(); 
} 
Cuestiones relacionadas