Pregunta

Estoy intentando realizar una consulta LINQ en un objeto DataTable y, curiosamente, encuentro que realizar este tipo de consultas en DataTables no es sencillo.Por ejemplo:

var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;

Esto no esta permitido.¿Cómo hago para que algo como esto funcione?

¡Me sorprende que las consultas LINQ no estén permitidas en DataTables!

¿Fue útil?

Solución

No puedes consultar contra el DataTable's Filas colección, desde DataRowCollection no implementa IEnumerable<T>.Necesitas usar el AsEnumerable() extensión para DataTable.Al igual que:

var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("RowNo") == 1
select myRow;

Y como dice Keith, deberás agregar una referencia a Extensiones System.Data.DataSet

AsEnumerable() devoluciones IEnumerable<DataRow>.Si necesitas convertir IEnumerable<DataRow> a un DataTable, utilizar el CopyToDataTable() extensión.

A continuación se muestra la consulta con expresión Lambda,

var result = myDataTable
    .AsEnumerable()
    .Where(myRow => myRow.Field<int>("RowNo") == 1);

Otros consejos

var results = from DataRow myRow in myDataTable.Rows
    where (int)myRow["RowNo"] == 1
    select myRow

No es que no se permitieran deliberadamente en DataTables, es solo que DataTables son anteriores a las construcciones IQueryable y IEnumerable genéricas en las que se pueden realizar consultas Linq.

Ambas interfaces requieren alguna validación de seguridad de tipos.Las tablas de datos no están fuertemente tipadas.Esta es la misma razón por la que las personas no pueden consultar una ArrayList, por ejemplo.

Para que Linq funcione, necesita asignar sus resultados a objetos con seguridad de tipos y consultarlos en su lugar.

Como dijo @ch00k:

using System.Data; //needed for the extension methods to work

...

var results = 
    from myRow in myDataTable.Rows 
    where myRow.Field<int>("RowNo") == 1 
    select myRow; //select the thing you want, not the collection

También es necesario agregar una referencia del proyecto a System.Data.DataSetExtensions

var query = from p in dt.AsEnumerable()
                    where p.Field<string>("code") == this.txtCat.Text
                    select new
                    {
                        name = p.Field<string>("name"),
                        age= p.Field<int>("age")                         
                    };

Me doy cuenta de que esto ha sido respondido varias veces, pero solo para ofrecer otro enfoque, me gusta usar el .Cast<T>() método, me ayuda a mantener la cordura al ver el tipo explícito definido, y en el fondo creo .AsEnumerable() lo llama de todos modos:

var results = from myRow in myDataTable.Rows.Cast<DataRow>()
                  where myRow.Field<int>("RowNo") == 1 select myRow;

o

var results = myDataTable.Rows.Cast<DataRow>()
                  .FirstOrDefault(x => x.Field<int>("RowNo") == 1);
//Create DataTable 
DataTable dt= new DataTable();
dt.Columns.AddRange(New DataColumn[]
{
   new DataColumn("ID",typeOf(System.Int32)),
   new DataColumn("Name",typeOf(System.String))

});

//Fill with data

dt.Rows.Add(new Object[]{1,"Test1"});
dt.Rows.Add(new Object[]{2,"Test2"});

//Now  Query DataTable with linq
//To work with linq it should required our source implement IEnumerable interface.
//But DataTable not Implement IEnumerable interface
//So we call DataTable Extension method  i.e AsEnumerable() this will return EnumerableRowCollection<DataRow>


// Now Query DataTable to find Row whoes ID=1

DataRow drow = dt.AsEnumerable().Where(p=>p.Field<Int32>(0)==1).FirstOrDefault();
 // 

Usando LINQ para manipular datos en DataSet/DataTable

var results = from myRow in tblCurrentStock.AsEnumerable()
              where myRow.Field<string>("item_name").ToUpper().StartsWith(tbSearchItem.Text.ToUpper())
              select myRow;
DataView view = results.AsDataView();

Pruebe esta sencilla línea de consulta:

var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);

Puedes usar LINQ para objetos en la colección Filas, así:

var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;

Prueba esto

var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ; 

Esta es una forma sencilla que me funciona y utiliza expresiones lambda:

var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)

Entonces si quieres un valor particular:

if(results != null) 
    var foo = results["ColName"].ToString()

Lo más probable es que las clases para DataSet, DataTable y DataRow ya estén definidas en la solución.Si ese es el caso, no necesitará la referencia de DataSetExtensions.

Ex.Nombre de clase DataSet-> CustomSet, nombre de clase DataRow-> CustomTableRow (con columnas definidas:FilaNo, ...)

var result = from myRow in myDataTable.Rows.OfType<CustomSet.CustomTableRow>()
             where myRow.RowNo == 1
             select myRow;

O (como prefiero)

var result = myDataTable.Rows.OfType<CustomSet.CustomTableRow>().Where(myRow => myRow.RowNo);
var results = from myRow in myDataTable
where results.Field<Int32>("RowNo") == 1
select results;

En mi aplicación descubrí que usar LINQ to Datasets con la extensión AsEnumerable() para DataTable como se sugiere en la respuesta era extremadamente lento.Si está interesado en optimizar la velocidad, utilice la biblioteca Json.Net de James Newtonking (http://james.newtonking.com/json/help/index.html)

// Serialize the DataTable to a json string
string serializedTable = JsonConvert.SerializeObject(myDataTable);    
Jarray dataRows = Jarray.Parse(serializedTable);

// Run the LINQ query
List<JToken> results = (from row in dataRows
                    where (int) row["ans_key"] == 42
                    select row).ToList();

// If you need the results to be in a DataTable
string jsonResults = JsonConvert.SerializeObject(results);
DataTable resultsTable = JsonConvert.DeserializeObject<DataTable>(jsonResults);

A continuación se proporciona un ejemplo de cómo lograr esto:

DataSet dataSet = new DataSet(); //Create a dataset
dataSet = _DataEntryDataLayer.ReadResults(); //Call to the dataLayer to return the data

//LINQ query on a DataTable
var dataList = dataSet.Tables["DataTable"]
              .AsEnumerable()
              .Select(i => new
              {
                 ID = i["ID"],
                 Name = i["Name"]
               }).ToList();

Para VB.NET el código se verá así:

Dim results = From myRow In myDataTable  
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow
IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
                             select myRow["server"].ToString() ;

Prueba esto...

SqlCommand cmd = new SqlCommand( "Select * from Employee",con);
SqlDataReader dr = cmd.ExecuteReader( );
DataTable dt = new DataTable( "Employee" );
dt.Load( dr );
var Data = dt.AsEnumerable( );
var names = from emp in Data select emp.Field<String>( dt.Columns[1] );
foreach( var name in names )
{
    Console.WriteLine( name );
}

Puedes hacerlo funcionar elegantemente a través de linq de esta manera:

from prod in TenMostExpensiveProducts().Tables[0].AsEnumerable()
where prod.Field<decimal>("UnitPrice") > 62.500M
select prod

O como linq dinámico esto (AsDynamic se llama directamente en DataSet):

TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)

Prefiero el último enfoque, aunque es el más flexible.PD.:No olvides conectarte System.Data.DataSetExtensions.dll referencia

Puedes intentar esto, pero debes estar seguro del tipo de valores para cada columna.

List<MyClass> result = myDataTable.AsEnumerable().Select(x=> new MyClass(){
     Property1 = (string)x.Field<string>("ColumnName1"),
     Property2 = (int)x.Field<int>("ColumnName2"),
     Property3 = (bool)x.Field<bool>("ColumnName3"),    
});
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top