Вопрос по .net, c#, linq – LINQ-запрос к DataTable

946

Я пытаюсь выполнить запрос LINQ для объекта DataTable, и странным образом обнаруживаю, что выполнение таких запросов к объектам DataTable не является простым. Например:

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

Это не разрешено Как мне получить что-то подобное?

Я поражен тем, что запросы LINQ не допускаются в DataTables!

Вы можете найти больше примеров LINQ / Lambda отwebmingle.blogspot.com/2010_09_01_archive.html user562221
Вы хотите то, что известно какLINQ to DataSet, Эта ссылка приведет вас к первой из серии публикаций, представленных в блоге команды ADO.NET. Matt Hamilton

Ваш Ответ

21   ответ
121

var results = from DataRow myRow in myDataTable.Rows
    where (int)myRow["RowNo"] == 1
    select myRow
Да, вот как я это делаю, кроме замены(int)myRow["RowNo"] с общей формойmyRow.Field<int>("RowNo") более удобно поддерживать обнуляемые типы.
Как насчет выбора нескольких строк, а не только строки 1?
Просто удалите & quot; где & quot; линия, и вы получите все строки
15

например так:

var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
@onedaywhen Я только что видел, как это делается в каком-то коде, и он компилируется. Пытаюсь выяснить почему именно сейчас.
Так какDataTable.Rows не реализуетIEnumerableЯ не вижу, как этот запрос может скомпилироваться.
не работал для меня.
26

Использование LINQ для манипулирования данными в DataSet / DataTable

              where myRow.Field<string>("item_name").ToUpper().StartsWith(tbSearchItem.Text.ToUpper())
              select myRow;
DataView view = results.AsDataView();
AsDataView не появляется в Intellisense для меня. Я включил использование System.Data.Linq и использование System.Linq, но он все еще не работает. Вы знаете, что мне не хватает? Заранее спасибо.
@ НаомиSystem.Data.DataSetExtensions.
48

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

10

классы для DataSet, DataTable и DataRow уже определены в решении. Если это так, то вам не нужна ссылка DataSetExtensions.

Ex. Имя класса DataSet- & gt; CustomSet, имя класса DataRow- & gt; 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);
16

var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
Я предпочитаю & quot;Method Chaining& Quot; (как вы сделали здесь) над & quot;Query Syntax& Quot; (в принятом ответе) просто потому, что это базовое предложение where, которое помещается в одну строку и все еще очень читабельно. Каждому свое.
6

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();
4

но вы должны быть уверены, что тип значений для каждого столбца

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"),    
});
Мир сошел с ума? Что не так с sql? DataRow [] drs = dt.Select (& quot; id = 1 & quot;); Может быть, это слишком просто.
6

IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
                             select myRow["server"].ToString() ;
6

что использование LINQ to Datasets с расширением AsEnumerable () для DataTable, как было предложено в ответе, было чрезвычайно медленным. Если вы заинтересованы в оптимизации скорости, воспользуйтесь библиотекой 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);
@an phu, используя метод расширения .AsEnumerable создает коллекцию тяжеловесовSystem.Data.DataRow объекты. Таблица сериализованных и проанализированных данных создает облегченные данные, состоящие только из имен столбцов и значений каждой строки. Когда запрос выполняется, он загружает данные в память, что для большого набора данных может включать обмен. Иногда затраты на выполнение нескольких операций меньше, чем на копирование больших объемов данных в память и из нее.
Я сомневаюсь, что это быстрее, в общих случаях. Это накладные расходы на две сериализации, одну десериализацию и одну операцию синтаксического анализа. Несмотря на это, я высказался против, потому что он не является кратким, то есть сериализация / десериализация не дает понять, что цель состоит в том, чтобы фильтровать список.
5

м:

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

Или как динамический linq this (AsDynamic вызывается непосредственно в DataSet):

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

Я предпочитаю последний подход, пока он самый гибкий. P.S .: Не забудьте подключитьсяSystem.Data.DataSetExtensions.dll ссылка

10

который работает для меня и использует лямбда-выражения:

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

Тогда, если вы хотите конкретное значение:

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

DataTable& APOS; sRows коллекция, так какDataRowCollection не реализуетIEnumerable<T>, Вам нужно использоватьAsEnumerable() расширение дляDataTable, Вот так:

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() расширение.

Ниже приведен запрос с лямбда-выражением,

var result = myDataTable
    .AsEnumerable()
    .Where(myRow => myRow.Field<int>("RowNo") == 1);
У меня уже была ссылка на упомянутую dll, но не хваталоusing System.Data;
@Markus Просто чтобы прояснить причину, по которой решение @ JoelFan работает сmyDataTable.Rows потому чтоmyRow переменная явно приведена кDataRow, Когда он компилируется, этот запрос переписываетсяmyDataTable.Rows.Cast<DataRow>().Where(myRow => (int)myRow["RowNo"] == 1), Лично я не нахожу звонокAsEnumerable() сложнее, чем призыв кCast<DataRow>(), Насколько я знаю, производительность одинакова, поэтому это просто вопрос предпочтений.
это решение излишне сложно. использованиеmyDataTable.Rows вместо этого, как предложил @JoelFan.
Версия VB: Dim results = From myRow In myDataTable.AsEnumerable _ Где myRow.Field (& quot; RowNo & quot;) = 1 _ Выбрать myRow
Версия VB должна быть вставлена (Of String) между myRow.Field и (& quot; RowNo & quot;). Эта часть должна выглядеть следующим образом: myRow.Field (Of String) (& quot; RowNo & quot;) = 1 - ссылка @Cros комментарий.
24

что на это уже отвечали несколько раз, но просто чтобы предложить другой подход, мне нравится использовать.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);
Это работает без ссылки на System.Data.DataSetExtensions.
26

//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();
 // 
9

var results = from myRow in myDataTable
where results.Field<Int32>("RowNo") == 1
select results;
Этот ответ так же много вопросов с ним.
65

что они были намеренно запрещены для DataTables, просто для того, чтобы DataTable предшествовали IQueryable и универсальным конструкциям IEnumerable, для которых могут выполняться запросы Linq.

Оба интерфейса требуют некоторой проверки безопасности типа. DataTables не являются строго типизированными. Это та же самая причина, почему люди не могут, например, запрашивать ArrayList.

Чтобы Linq работал, вам нужно сопоставить результаты с типобезопасными объектами и вместо этого выполнить запрос.

11

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

Dim results = From myRow In myDataTable  
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow
37

var query = from p in dt.AsEnumerable()
                    where p.Field&,lt;string>("code") == this.txtCat.Text
                    select new
                    {
                        name = p.Field<string>("name"),
                        age= p.Field<int>("age")                         
                    };
Как я использую имя? Например,MessageBox.Show(name) не определено
5

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 );
}

Похожие вопросы