DataTable에 대한 LINQ 쿼리


1031

DataTable 개체에서 LINQ 쿼리를 수행하려고하는데 기이하게 DataTables에서 이러한 쿼리를 수행하는 것이 간단하지 않다는 것을 알게되었습니다. 예를 들면 다음과 같습니다.

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

이것은 허용되지 않습니다. 이처럼 작동하는 것을 어떻게 얻습니까?

LINQ 쿼리가 DataTables에 허용되지 않는다는 것에 놀랐습니다!


답변:


1279

DataTable 컬렉션 에 대해 쿼리 할 수 ​​없습니다 . DataRowCollection구현하지 않기 때문 IEnumerable<T>입니다. 의 AsEnumerable()확장명 을 사용해야합니다 DataTable. 이렇게 :

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

로 그리고 @Keith는 말한다, 당신에 대한 참조를 추가해야합니다 System.Data.DataSetExtensions을

AsEnumerable()을 반환합니다 IEnumerable<DataRow>. 당신이 변환해야하는 경우 IEnumerable<DataRow>A를 DataTable, 사용 CopyToDataTable()연장.

다음은 Lambda Expression을 사용한 쿼리입니다.

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

8
VB 버전 : Dim 결과 = myRowTable에서 myDataTable.AsEnumerable _ 여기서 myRow.Field ( "RowNo") = 1 _ myRow 선택
Jeff

15
이미 언급 한 dll에 대한 참조가 있었지만 누락되었습니다using System.Data;
Luke Duddridge

5
VB 버전은 myRow.Field와 ( "RowNo") 사이에 (Of String)을 삽입해야합니다. 이 부분은 다음과 같아야합니다. myRow.Field (Of String) ( "RowNo") = 1-Reference @Cros comment.
yougotiger

8
이 솔루션은 불필요하게 복잡합니다. myDataTable.Rows@JoelFan이 제안한대로 대신 사용하십시오 .
음모

10
@Markus 명확히하기 위해, @JoelFan의 솔루션이 작동하는 myDataTable.Rows이유는 myRow변수가 명시 적으로로 캐스팅 되었기 때문 DataRow입니다. 컴파일되면 해당 쿼리가로 다시 작성됩니다 myDataTable.Rows.Cast<DataRow>().Where(myRow => (int)myRow["RowNo"] == 1). 개인적으로에 대한 호출 AsEnumerable()보다 복잡한 호출을 찾지 못했습니다 Cast<DataRow>(). 내가 아는 한 성능은 동일하므로 선호의 문제 일뿐입니다.
Collin K

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

2
행 1 대신 여러 행을 선택하는 것은 어떻습니까?
Adjit

2
"where"줄을 제거하면 모든 행을 얻게됩니다
JoelFan

1
예, null을 사용하는 유형을보다 편리하게 지원하기 위해 (int)myRow["RowNo"]일반 형식 myRow.Field<int>("RowNo")으로 바꾸는 것을 제외 하고는이 방법을 사용합니다 .
Jonas

69

DataTable에서 의도적으로 허용되지 않았을뿐만 아니라, Linq 쿼리를 수행 할 수있는 IQueryable 및 일반 IEnumerable 구문보다 DataTables가 최신 버전 일뿐입니다.

두 인터페이스 모두 일종의 형식 안전 유효성 검사가 필요합니다. DataTable은 강력하게 형식화되지 않았습니다. 예를 들어 사람들이 ArrayList에 대해 쿼리 할 수없는 것과 같은 이유입니다.

Linq가 작동하려면 결과를 형식이 안전한 개체에 매핑하고 대신 쿼리해야합니다.


49

@ 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


1
당신이 시도 할 경우에 특정 유형을 넣어하지 않는 한, 당신은 작동하지 않습니다 찾을 수 있습니다 myRow또는 사용 Cast<DataRow>()Rows. 사용하는 것이 좋습니다 AsEnumerable().
NetMage

1
@NetMage 이것은 12 년 전에 게시했을 때 작동했습니다. 만큼 당신이 가지고 System.LinqSystem.Data.DataSetExtensions다음 myDataTable.Rows의 열거 가능한 컬렉션을 반환 DataRow어쨌든. 내가 사용한지 10 년이 지났을 수도 있습니다.
키이스

1
흥미 롭습니다. 현재 .Net 또는 .Net Core에서 작동하지 않으므로 어느 시점에서 변경 된 것 같습니다.
NetMage

1
@NetMage 예, DataSet확장 프로그램이 .NET Core 또는 .NET Standard로 만들지 않았다는 사실에 놀라지 않습니다.이 답변을 게시했을 때 이미 구식이었습니다. 나는 DataSet새로운 프로젝트에서 실제로 사용하지 않을 것이고 , 코딩 및 성능의 용이성을 위해 훨씬 더 나은 데이터 액세스 모델이 있습니다.
Keith

1
그들은이 있지만 DataRowCollection구현하지 않습니다 IEnumerable<T>단지 IEnumerable등 강력한 형식의 LINQ와 작업을하지 않습니다.
NetMage

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

이름 및 연령 필드는 이제 쿼리 개체의 일부이며 다음과 같이 액세스 할 수 있습니다. Console.WriteLine (query.name);


이름은 어떻게 사용합니까? 예를 들어, MessageBox.Show(name)정의되지 않았습니다.

35

나는 이것이 몇 번 이상 대답되었지만 다른 접근 방식을 제공한다는 것을 알고 있습니다.

나는이 .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);

의견에서 언급했듯이 Linq의 일부이므로 다른 어셈블리가 필요하지 않습니다 ( Reference )


5
System.Data.DataSetExtensions를 참조하지 않고 작동합니다.
user423430

29

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

1
AsDataView가 Intellisense에 나타나지 않습니다. System.Data.Linq 및 System.Linq 사용을 포함했지만 여전히 작동하지 않습니다. 내가 뭘 놓치고 있는지 알아? 미리 감사드립니다.
나오미

@Naomi 그것은에서 온다 System.Data.DataSetExtensions.
Louis Waweru

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

22

이 간단한 쿼리 줄을 사용해보십시오.

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

4
나는 한 줄에 맞는 기본적인 where-clause이기 때문에 여전히 읽기 쉬운 " 문의 구문 "(허용 된 답변에서 )보다 " 메소드 체인 "(여기에서 한 것처럼)을 선호합니다 . 각자 자신에게.
MikeTeeVee

16

LINQ를 사용하여 다음과 같이 Rows 컬렉션의 개체에 사용할 수 있습니다.

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

1
때문에 DataTable.Rows구현하지 않습니다 IEnumerable,이 쿼리가 컴파일 할 수있는 방법을 볼 수 없습니다.
onedaywhen

@ oneday 방금이 코드에서 수행되는 것을 보았을 때 컴파일됩니다. 왜 지금인지 알아 내려고 노력 중입니다.
BVernon

... 또는 Select 메서드 내에서 필터 식을 사용할 수 있습니다. var results = myDataTable.Select ( "RowNo = 1"); DataRow 배열을 반환합니다.
Ishikawa

12

이것은 나를 위해 작동하고 람다 식을 사용하는 간단한 방법입니다.

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

그런 다음 특정 값을 원하면

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

11

이 시도

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

11

DataSet, DataTable 및 DataRow의 클래스는 이미 솔루션에 정의되어 있습니다. 이 경우 DataSetExtensions 참조가 필요하지 않습니다.

전의. 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);

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

이 문제는 많은 문제로 대답합니다.
미스터 앤더슨

8

내 응용 프로그램에서 대답에 제안 된대로 DataTable의 AsEnumerable () 확장명을 사용하여 LINQ to Datasets를 사용하는 것이 매우 느리다는 것을 알았습니다. 속도 최적화에 관심이있는 경우 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);

나는 일반적인 경우에 이것이 더 빠르지 않다. 직렬화 해제와 구문 분석 작업의 두 가지 직렬화 오버 헤드가 있습니다. 그럼에도 불구하고, 나는 그것이 간결하지 않기 때문에 하향 투표했다.
phu

@an phu는 .AsEnumerable 확장 메소드를 사용하여 헤비급 System.Data.DataRow객체 의 모음을 만듭니다 . 직렬화되고 구문 분석 된 데이터 테이블은 각 행의 열 이름과 값으로 만 구성된 경량 데이터를 작성합니다. 쿼리가 실행되면 데이터가 메모리에로드되며, 대규모 데이터 세트의 경우 스왑이 필요할 수 있습니다. 때로는 여러 작업의 오버 헤드가 많은 양의 데이터를 메모리 안팎으로 복사하는 오버 헤드보다 적습니다.
LandedGently

7

VB.NET의 경우 코드는 다음과 같습니다.

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

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

7

이를 달성하는 방법에 대한 예는 다음과 같습니다.

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

6

이 시도...

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

5

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)

마지막 접근 방식을 선호하지만 가장 유연합니다. 추신 : System.Data.DataSetExtensions.dll참조 를 연결하는 것을 잊지 마십시오


5

시도해 볼 수 있지만 각 열의 값 유형을 확인해야합니다

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 ( "id = 1"); 어쩌면 이것은 너무 쉽습니다.
Programnik

0

다음 해결책을 제안합니다.

DataView view = new DataView(myDataTable); 
view.RowFilter = "RowNo = 1";
DataTable results = view.ToTable(true);

상기 찾고 DataView를 문서 , 우리가 볼 수있는 첫 번째 일은이 있습니다 :

정렬, 필터링, 검색, 편집 및 탐색을위한 DataTable의 데이터 바인딩 가능, 사용자 지정 뷰를 나타냅니다.

내가 얻은 것은 DataTable은 데이터를 저장하기위한 것이며 DataView는 DataTable에 대해 "쿼리"할 수 있다는 것입니다.

이 특별한 경우에 이것이 작동하는 방법은 다음과 같습니다.

당신은 SQL 문을 구현하려고

SELECT *
FROM myDataTable
WHERE RowNo = 1

"DataTable 언어"로 C #에서는 다음과 같이 읽습니다.

FROM myDataTable
WHERE RowNo = 1
SELECT *

C #에서 다음과 같이 보입니다.

DataView view = new DataView(myDataTable);  //FROM myDataTable
view.RowFilter = "RowNo = 1";  //WHERE RowNo = 1
DataTable results = view.ToTable(true);  //SELECT *

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});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.