DataTable에 대한 LINQ 쿼리
문제
DataTable 개체에 대해 LINQ 쿼리를 수행하려고 하는데 이상하게도 DataTables에서 이러한 쿼리를 수행하는 것이 간단하지 않다는 것을 알게 되었습니다.예를 들어:
var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;
이는 허용되지 않습니다.이와 같은 작업을 어떻게 수행합니까?
DataTables에서는 LINQ 쿼리가 허용되지 않는다는 사실에 놀랐습니다!
해결책
다음 항목에 대해 쿼리할 수 없습니다. 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>
에 DataTable
, 사용 CopyToDataTable()
확대.
아래는 Lambda 표현식을 사용한 쿼리입니다.
var result = myDataTable
.AsEnumerable()
.Where(myRow => myRow.Field<int>("RowNo") == 1);
다른 팁
var results = from DataRow myRow in myDataTable.Rows
where (int)myRow["RowNo"] == 1
select myRow
DataTables에서 의도적으로 허용되지 않은 것이 아니라 DataTables가 Linq 쿼리를 수행할 수 있는 IQueryable 및 일반 IEnumerable 구문보다 앞서 있다는 것입니다.
두 인터페이스 모두 일종의 유형 안전성 검증이 필요합니다.DataTable은 강력한 형식이 아닙니다.예를 들어 사람들이 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")
};
나는 이것이 몇 번에 걸쳐 답변되었다는 것을 알고 있지만 다른 접근 방식을 제공하기 위해 다음을 사용하고 싶습니다. .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);
//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();
다음과 같은 간단한 쿼리를 시도해 보세요.
var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
다음과 같이 Rows 컬렉션의 개체에 LINQ를 사용할 수 있습니다.
var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
이 시도
var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ;
이것은 나에게 적합하고 람다 표현식을 사용하는 간단한 방법입니다.
var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)
그런 다음 특정 값을 원하는 경우:
if(results != null)
var foo = results["ColName"].ToString()
아마도 DataSet, DataTable 및 DataRow에 대한 클래스가 이미 솔루션에 정의되어 있을 것입니다.이 경우 DataSetExtensions 참조가 필요하지 않습니다.
전.DataSet 클래스 이름-> CustomSet, DataRow 클래스 이름-> CustomTableRow(정의된 열 포함:행아니, ...)
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 = from myRow in myDataTable
where results.Field<Int32>("RowNo") == 1
select results;
내 응용 프로그램에서 답변에서 제안한 대로 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);
이를 달성하는 방법에 대한 예는 다음과 같습니다.
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();
VB.NET의 경우 코드는 다음과 같습니다.
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() ;
이 시도...
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)
나는 마지막 접근 방식을 선호하지만 이것이 가장 유연합니다.추신.:연결하는 것을 잊지 마세요 System.Data.DataSetExtensions.dll
참조
이것을 시도해 볼 수 있지만 각 열의 값 유형을 확인해야 합니다.
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"),
});