Я пытаюсь выполнить запрос LINQ в объекте DataTable, и я прихожу к выводу, что выполнение таких запросов в DataTables непросто. Например:
var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;
Это запрещено. Как мне получить что-то вроде этого?
Я поражен тем, что запросы LINQ не разрешены в DataTables!
Вы не можете запросить коллекцию строк DataTable
, так как DataRowCollection
не реализует IEnumerable<T>
. Для DataTable
необходимо использовать расширение AsEnumerable()
. Например:
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("RowNo") == 1
select myRow;
И как говорит Кейт, вам нужно добавить ссылку на System.Data.DataSetExtensions
AsEnumerable()
возвращает IEnumerable<DataRow>
. Если вам нужно преобразовать IEnumerable<DataRow>
в DataTable
, используйте расширение CopyToDataTable()
.
using System.Data;
var results = from DataRow myRow in myDataTable.Rows
where (int)myRow["RowNo"] == 1
select myRow
Не то, чтобы они не были преднамеренно запрещены в DataTables, это только то, что DataTables предваряют IQueryable и общие конструкторы IEnumerable, по которым могут выполняться запросы Linq.
Оба интерфейса требуют некоторой проверки безопасности типа. Таблицы данных не строго типизированы. Это по той же причине, почему люди не могут запрашивать ArrayList, например.
Для работы Linq вам нужно сопоставить ваши результаты с объектами, защищенными типом, и запросить их вместо этого.
Как сказал @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
Вам также необходимо добавить ссылку на проект 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")
};
MessageBox.Show(name)
не определено.
//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();
//
Использование LINQ для управления данными в 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();
System.Data.DataSetExtensions
.
Вы можете использовать LINQ для объектов в коллекции Rows, например:
var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
DataTable.Rows
не реализует IEnumerable
, я не вижу, как этот запрос может скомпилироваться.
Попробуйте эту простую строку запроса:
var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
Надеюсь, что это поможет;
Я понимаю, что это было несколько раз ответило, но просто для того, чтобы предложить другой подход, мне нравится использовать метод .Cast<T>()
, это помогает мне поддерживать здравомыслие, видя явный тип, определенный, и в глубине души я думаю, что .AsEnumerable()
вызывает это в любом случае:
var results = from myRow in myDataTable.Rows.Cast<DataRow>()
where myRow.Field<int>("RowNo") == 1 select myRow;
или
var results = myDataTable.Rows.Cast<DataRow>()
.FirstOrDefault(x => x.Field<int>("RowNo") == 1);
Попробуйте это
var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ;
Скорее всего, классы для DataSet, DataTable и DataRow уже определены в решении. Если в этом случае вам не понадобится ссылка DataSetExtensions.
Ex. Имя класса DataSet- > CustomSet, имя класса DataRow- > CustomTableRow (с определенными столбцами: RowNo,...)
var result = from myRow in myDataTable.Rows.OfType<CustomSet.CustomTableRow>()
where myRow.RowNo == 1
select myRow;
Или (как я предпочитаю)
var result = myDataTable.Rows.OfType<CustomSet.CustomTableRow>().Where(myRow => myRow.RowNo);
Счастливое кодирование!
Это простой способ, который работает для меня и использует лямбда-выражения:
var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)
Затем, если вы хотите получить определенное значение:
if(results != null)
var foo = results["ColName"].ToString()
var results = from myRow in myDataTable
where results.Field<Int32>("RowNo") == 1
select results;
Пример того, как это сделать, приведен ниже:
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();
IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
select myRow["server"].ToString() ;
В моем приложении я обнаружил, что использование LINQ to Datasets с расширением AsEnumerable() для DataTable, как было предложено в ответе, было очень медленным. Если вы заинтересованы в оптимизации скорости, используйте библиотеку James Newtonking Json.Net(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);
System.Data.DataRow
. Таблица сериализованных и проанализированных данных создает облегченные данные, состоящие только из имен столбцов и значений каждой строки. Когда запрос выполняется, он загружает данные в память, что для большого набора данных может включать обмен. Иногда накладные расходы на несколько операций меньше, чем накладные расходы на копирование больших объемов данных в память и из нее.
Для VB.NET Код будет выглядеть так:
Dim results = From myRow In myDataTable
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow
Попробуйте это...
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 );
}
Вы можете заставить его работать элегантно с помощью linq следующим образом:
from prod in TenMostExpensiveProducts().Tables[0].AsEnumerable()
where prod.Field<decimal>("UnitPrice") > 62.500M
select prod
Или как динамический linq это (AsDynamic вызывается непосредственно на DataSet):
TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)
Я предпочитаю последний подход, пока он является наиболее гибким.
P.S.: Не забудьте подключить System.Data.DataSetExtensions.dll
ссылку