Consulta LINQ en un DataTable
Frecuentes
Visto 973,452 equipos
1061
Estoy tratando de realizar una consulta LINQ en un objeto DataTable y, extrañamente, encuentro que realizar tales 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!
23 Respuestas
1314
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 @Keith dice, deberá agregar una referencia a Extensiones System.Data.DataSet
AsEnumerable()
devoluciones IEnumerable<DataRow>
. Si necesita convertir IEnumerable<DataRow>
a una DataTable
, utilizar el CopyToDataTable()
extensión.
A continuación se muestra una consulta con Lambda Expression,
var result = myDataTable
.AsEnumerable()
.Where(myRow => myRow.Field<int>("RowNo") == 1);
Respondido 06 Abr '20, 10:04
Versión de VB: Dim results = From myRow In myDataTable.AsEnumerable _ Where myRow.Field ("RowNo") = 1 _ Select myRow - Jeff
Ya tenía una referencia a la dll mencionada, pero faltaba using System.Data;
- Lucas Duddridge
VB Version necesita insertar (Of String) entre myRow.Field y ("RowNo"). Esa parte debe leer: myRow.Field (Of String) ("RowNo") = 1 - Comentario de referencia @Cros. - yougottiger
esta solución es innecesariamente complicada. Usar myDataTable.Rows
en su lugar, como sugirió @JoelFan. - La Conspiración
@Markus Solo para aclarar, la razón por la que la solución de @ JoelFan funciona con myDataTable.Rows
es porque el myRow
la variable se lanza explícitamente a DataRow
. Cuando se compila, esa consulta se reescribe a myDataTable.Rows.Cast<DataRow>().Where(myRow => (int)myRow["RowNo"] == 1)
. Personalmente, no encuentro la llamada para AsEnumerable()
más complicado que la llamada a Cast<DataRow>()
. Hasta donde yo sé, el rendimiento es el mismo, por lo que es solo una cuestión de preferencia. - colin k
133
var results = from DataRow myRow in myDataTable.Rows
where (int)myRow["RowNo"] == 1
select myRow
respondido 05 mar '09, 02:03
¿Qué pasa con la selección de varias filas, en lugar de solo la fila 1? - Ajustar
Simplemente elimine la línea "dónde" y obtendrá todas las filas: joelfan
Sí, así es como lo hago, excepto para reemplazar (int)myRow["RowNo"]
con la forma genérica myRow.Field<int>("RowNo")
para admitir de forma más conveniente tipos que aceptan valores NULL. - Jonas
70
No es que no se hayan permitido deliberadamente en DataTables, es solo que DataTables es anterior a las construcciones IQueryable y IEnumerable genéricas en las que se pueden realizar consultas de Linq.
Ambas interfaces requieren algún tipo de validación de seguridad de tipo. 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, debe mapear sus resultados con objetos de tipo seguro y consultarlos en su lugar.
Respondido 14 ago 08, 11:08
52
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 debe agregar una referencia de proyecto a System.Data.DataSetExtensions
Respondido 14 ago 08, 12:08
Si prueba esto, encontrará que no funcionará a menos que ponga un tipo específico en myRow
vea la sección Cast<DataRow>()
on Rows
. Mejor usar AsEnumerable()
. - Mago de red
@NetMage esto funcionó hace 12 años cuando lo publiqué. Mientras tengas System.Linq
e System.Data.DataSetExtensions
luego myDataTable.Rows
devuelve una colección enumerable de DataRow
de todas formas. Eso podría haber cambiado, ha pasado una década desde que lo usé. - Keith
Interesante: supongo que se cambió en algún momento, ya que ahora no funciona en .Net o .Net Core. - Mago de red
@NetMage sí, no me sorprende el DataSet
Las extensiones no llegaron a .NET Core o .NET Standard, ya estaban desactualizadas cuando publiqué esta respuesta. Realmente no lo usaría DataSet
en proyectos nuevos, existen modelos de acceso a datos mucho mejores, tanto para facilitar la codificación como para el rendimiento. - Keith
Están ahí, pero DataRowCollection
no implementa IEnumerable<T>
solo IEnumerable
por lo que no funciona con LINQ fuertemente tipado. - Mago de red
40
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")
};
los campos de nombre y edad ahora son parte del objeto de consulta y se puede acceder a ellos así: Console.WriteLine (query.name);
respondido 23 nov., 19:13
¿Cómo uso el nombre? Por ejemplo, MessageBox.Show(name)
es indefinido. - usuario1372430
38
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;
or
var results = myDataTable.Rows.Cast<DataRow>()
.FirstOrDefault(x => x.Field<int>("RowNo") == 1);
Como se señaló en los comentarios, no se necesitan otros ensamblajes ya que es parte de Linq (Referencia)
Respondido el 20 de junio de 20 a las 10:06
Esto funciona sin hacer referencia a System.Data.DataSetExtensions. - user423430
30
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();
Respondido 11 Feb 14, 04:02
El AsDataView no aparece en Intellisense para mí. Incluí el uso de System.Data.Linq y el uso de System.Linq, pero aún no funciona. ¿Sabes lo que me estoy perdiendo? Gracias por adelantado. - Naomi
@Naomi Viene de System.Data.DataSetExtensions
. - Luis Waweru
30
//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();
//
Respondido el 11 de diciembre de 19 a las 08:12
24
Pruebe esta sencilla línea de consulta:
var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
Respondido el 15 de diciembre de 17 a las 12:12
Prefiero el "Encadenamiento de métodos"(como ha hecho aquí) sobre el"Sintaxis de la consulta"(en la respuesta aceptada) simplemente porque esta es una cláusula where básica que cabe en una línea y aún es muy legible. Para cada uno lo suyo. - miketevee
17
Puede usar LINQ para objetos en la colección Rows, así:
var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
Respondido 14 ago 08, 11:08
Gracias DataTable.Rows
no implementa IEnumerable
, No veo cómo se podría compilar esta consulta. - un día cuando
@onedaywhen acabo de ver que esto se hace en un código y se compila. Tratando de averiguar por qué ahora mismo. - Vernon
... o simplemente puede usar una expresión de filtro dentro del método Select: var results = myDataTable.Select ("RowNo = 1"); Esto devuelve una matriz DataRow. - Ishikawa
14
Esta es una forma simple que funciona para mí y usa expresiones lambda:
var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)
Entonces, si quieres un valor en particular:
if(results != null)
var foo = results["ColName"].ToString()
respondido 18 mar '15, 22:03
11
Prueba esta
var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ;
contestado el 18 de mayo de 12 a las 08:05
11
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 DataSetExtensions.
Ex. Nombre de clase de DataSet-> CustomSet, nombre de clase de DataRow-> CustomTableRow (con columnas definidas: RowNo, ...)
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);
Respondido el 15 de diciembre de 17 a las 12:12
9
var results = from myRow in myDataTable
where results.Field<Int32>("RowNo") == 1
select results;
Respondido 01 Feb 14, 12:02
Esta respuesta tiene muchos problemas. - Sr. Anderson
8
En mi aplicación, encontré 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, use 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);
Respondido 14 Oct 14, 18:10
Dudo que esto sea más rápido, en los casos generales. Tiene la sobrecarga de dos operaciones de serialización, una deserialización y una de análisis. Independientemente, voté en contra porque no es conciso, es decir, la serialización / deserialización no deja en claro que la intención es filtrar una lista. - un phu
@an phu, el uso del método de extensión .AsEnumerable crea una colección de pesos pesados System.Data.DataRow
objetos. La tabla de datos serializados y analizados crea datos ligeros que constan solo de los nombres de columna y los valores de cada fila. Cuando se ejecuta la consulta, cargará los datos en la memoria, lo que para un conjunto de datos grande puede implicar un intercambio. A veces, la sobrecarga de varias operaciones es menor que la sobrecarga de copiar grandes cantidades de datos dentro y fuera de la memoria. - Aterrizó gentilmente
8
Ejemplo de cómo lograr esto se proporciona a continuación:
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();
Respondido 25 Oct 17, 17:10
7
Para VB.NET, el código se verá así:
Dim results = From myRow In myDataTable
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow
Respondido 11 Feb 14, 04:02
7
IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
select myRow["server"].ToString() ;
Respondido 04 ago 15, 08:08
6
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 );
}
Respondido 20 Abr '17, 15:04
5
Puede hacer que funcione de manera elegante 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 dynamic linq this (AsDynamic se llama directamente en DataSet):
TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)
Prefiero el último enfoque mientras que es el más flexible. PD: no olvides conectarte System.Data.DataSetExtensions.dll
referencia
respondido 06 nov., 13:09
5
puede probar esto, pero debe asegurarse de que el 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"),
});
Respondido el 25 de Septiembre de 18 a las 15:09
¿Se ha vuelto loco el mundo? ¿Qué pasa con sql? DataRow [] drs = dt.Select ("id = 1"); Quizás esto sea demasiado fácil. - Programa
0
Propongo la siguiente solución:
DataView view = new DataView(myDataTable);
view.RowFilter = "RowNo = 1";
DataTable results = view.ToTable(true);
En cuanto al Documentación de DataView, lo primero que podemos ver es esto:
Representa una vista personalizada y enlazable de datos de una tabla de datos para ordenar, filtrar, buscar, editar y navegar.
Lo que obtengo de esto es que DataTable está destinado a almacenar solo datos y DataView nos permite "consultar" contra el DataTable.
Así es como funciona esto en este caso particular:
Intentas implementar la declaración SQL
SELECT *
FROM myDataTable
WHERE RowNo = 1
en "lenguaje DataTable". En C # lo leeríamos así:
FROM myDataTable
WHERE RowNo = 1
SELECT *
que se ve en C # así:
DataView view = new DataView(myDataTable); //FROM myDataTable
view.RowFilter = "RowNo = 1"; //WHERE RowNo = 1
DataTable results = view.ToTable(true); //SELECT *
Respondido 19 ago 19, 15:08
0
//Json Formating code
//DT is DataTable
var filter = (from r1 in DT.AsEnumerable()
//Grouping by multiple columns
group r1 by new
{
EMPID = r1.Field<string>("EMPID"),
EMPNAME = r1.Field<string>("EMPNAME"),
} into g
//Selecting as new type
select new
{
EMPID = g.Key.EMPID,
MiddleName = g.Key.EMPNAME});
Respondido el 22 de diciembre de 19 a las 13:12
Puede encontrar más ejemplos de LINQ / Lambda en webmingle.blogspot.com/2010_09_01_archive.html - user562221
Es porque las tablas de datos son anteriores a LINQ por algunos años. En su lugar, utilice una tabla de datos fuertemente tipada; una mejor experiencia en general que esta cadena de caracteres, que derrota al intellisense
dt.Rows["FirstName]
basura .. Con una tabla fuertemente tipada (agregue un archivo de tipo DataSet a su proyecto y cree tablas dentro de él en el diseñador visual) simplemente escriba, por ejemplomyStronglyTpedDataset.Person.Where(p => p.FirstName == "John")
- toda la magia para que esto suceda ya está hecha - Caius Jard