I have a dataTable with 4 columns ,
I want to select one column without foreach or any other expensive loop and my result must be a new data table with one column ,How can I do this;
DataTable leaveTypesPerPersonnel = LeaveGroup.GetLeaveTypesPerPersonnels(dtPersonnel.row);
leaveTypesPerPersonnel has this columns :
[ID,Guid,LeaveTypeID,Code]
I want Filter leaveTypesPerPersonnel wihtout foreach and get new datatable with just Column [ID]
NOTE: Output must be a Datatable With one column.
leaveTypesPerPersonnel.Columns.Remove("Guid");
leaveTypesPerPersonnel.Columns.Remove("LeaveTypeID");
leaveTypesPerPersonnel.Columns.Remove("Code");
or
DataTable dt= new DataView(leaveTypesPerPersonnel).ToTable(false,"ID");
You should be able to run a quick LINQ statement against the data table.
var results = (from item in leaveTypesPerPersonnel
select item.ID);
This will give you an IEnumerable if I remember correctly. It's not a DataTable, but might provide a solution to your problem as well.
Here is a try on how to search and convert the result to DataTable
var dataTable = leaveTypesPerPersonnel.Rows.Cast<DataRow>().ToList().Where(x=> x["ID"] == 21).CopyToDataTable().DefaultView.ToTable(false, "ID");
Or
var dataTable = leaveTypesPerPersonnel.Select("ID = 21").CopyToDataTable().DefaultView.ToTable(false, "ID");
Or
var dataTable = leaveTypesPerPersonnel.Rows.Cast<DataRow>().ToList().CopyToDataTable().DefaultView.ToTable(false, "ID");
Here i want to find the Matched Records From Two data tables. the code is
public DataTable textfiltering(DataTable dtfff, DataTable dtff)
{
DataTable ds = (DataTable)Session["maintxt"];
DataTable dts = (DataTable)Session["sectxt"];
dtfff = ds;
dtff = dts;
DataTable dtMerged = (from a in dtfff.AsEnumerable()
join b in dtff.AsEnumerable()
on a["contacts"].ToString() equals b["contacts"].ToString()
into g
where g.Count()>0
select a).CopyToDataTable();
return dtMerged;
}
it gives "The source contains no DataRows" when Data tables does not contain Matched Records...
How to rectify it..pls give your suggistions
Two ways:
either check if it contains rows with Enumerable.Any before you call CopyToDataTable
use dtfff.Clone to create an empty DataTable with the same schema as the source table and use a loop to fill it from the LINQ query.
First approach:
var rows = from a in dtfff.AsEnumerable()
join b in dtff.AsEnumerable()
on a["contacts"].ToString() equals b["contacts"].ToString()
into g
where g.Count() > 0
select a;
DataTable merged;
if (rows.Any())
merged = rows.CopyToDataTable();
else
merged = dtfff.Clone();
return merged;
Second approach:
DataTable merged = dtfff.Clone();
foreach (DataRow sourceRow in rows)
{
merged.ImportRow(sourceRow); // or add all fields manually
}
return merged;
I prefer the second approach since it only needs to execute the query once.
This is my code:
SqlCommand vmpCmd = new SqlCommand("sp", connectionstring);
SqlDataAdapter DAvmp = new SqlDataAdapter(vmpCmd);
DataSet DSvmp = new DataSet();
DSvmp.Clear();
DAvmp.Fill(DSvmp);
DataTable table;
table = DSvmp.Tables[0];
from that table I need to take all the rows that its Campaign column exists in this list List<string> compaines = new List<string>();
What have I tried
I tried this:
table = (from row in table.AsEnumerable()
where compaines.Contains(row.Field<string>("Campaign"))
select row);
but I got this exception on the select:
Cannot implicitly convert type 'System.Data.EnumerableRowCollection<System.Data.DataRow>' to 'System.Data.DataTable'
If you want to convert an IEnumerable<DataRow> to a DataTable you can use CopyToDataTable:
var filteredRows = table.AsEnumerable()
.Where(row => compaines.Contains(row.Field<string>("Campaign")));
table = filteredRows.CopyToDataTable();
But instead of filtering when you've already retrieved all records i would do that in the database. Here's a nice trick to build parameters from a List<string>.
Use CopyToDataTable extension method to convert IEnumerable<DataRow> to DataTable
table = (from row in table.AsEnumerable()
where compaines.Contains(row.Field<string>("Campaign"))
select row).CopyToDataTable();
Get the values in var data type like this as LINQ returns System.Data.EnumerableRowCollection<System.Data.DataRow which cannot be implicity converted to Datatable type
var filteredTable = (from row in table.AsEnumerable()
where compaines.Contains(row.Field<string>("Campaign"))
select row);
If you want the retrieved records for other operations then its fine otherwise it's better to use filter in your query and for that there are below methods:
You can use parameterized query
You can build your query string using String.Join() from your List
I have a DataTable named dt2 with data. I am calling its Select method to get some specific rows.
DataRow[] foundRows;
expression = "parent_id=1";
foundRows = dt2.Select(expression);
How can I pass the Select-method result to a new DataTable – say FilteredData?
You can use CopyToDataTable, available on IEnumerable<DataRow> types.
var filteredData = dt2.Select(expression).CopyToDataTable();
Just for clarity, the Select method returns an array of type DataRow. That's why we need to use CopyToDataTable(). Alex's answer is good. However, if the Select didn't return any rows, CopyToDataTable() will throw an InvalidOperationException.
So test that there is at least one DataRow before using the CopyToDataTable().
var filteredDataRows = dt2.Select(expression);
var filteredDataTable = new DataTable();
if(filteredDataRows.Length != 0)
filteredDataTable = filteredDataRows.CopyToDataTable();
Why not use a DataView instead?
DataView view = new DataView(dt2);
view.RowFilter = "parent_id = 1";
DataView will behave in very much the same way that a DataTable would with the added benefit that any change(s) to the underlying DataTable (dt2 in this case) would be automatically reflected in the DataView.
I'm trying to perform a LINQ query on a DataTable object and bizarrely I am finding that performing such queries on DataTables is not straightforward. For example:
var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;
This is not allowed. How do I get something like this working?
I'm amazed that LINQ queries are not allowed on DataTables!
You can't query against the DataTable's Rows collection, since DataRowCollection doesn't implement IEnumerable<T>. You need to use the AsEnumerable() extension for DataTable. Like so:
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("RowNo") == 1
select myRow;
And as #Keith says, you'll need to add a reference to System.Data.DataSetExtensions
AsEnumerable() returns IEnumerable<DataRow>. If you need to convert IEnumerable<DataRow> to a DataTable, use the CopyToDataTable() extension.
Below is query with Lambda Expression,
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
It's not that they were deliberately not allowed on DataTables, it's just that DataTables pre-date the IQueryable and generic IEnumerable constructs on which Linq queries can be performed.
Both interfaces require some sort type-safety validation. DataTables are not strongly typed. This is the same reason why people can't query against an ArrayList, for example.
For Linq to work you need to map your results against type-safe objects and query against that instead.
As #ch00k said:
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
You also need to add a project reference to System.Data.DataSetExtensions
I realize this has been answered a few times over, but just to offer another approach:
I like to use the .Cast<T>() method, it helps me maintain sanity in seeing the explicit type defined and deep down I think .AsEnumerable() calls it anyways:
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);
As noted in comments, does not require System.Data.DataSetExtensions or any other assemblies (Reference)
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")
};
the name and age fields are now part of the query object and can be accessed like so: Console.WriteLine(query.name);
Using LINQ to manipulate data in 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();
//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();
//
Try this simple line of query:
var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
You can use LINQ to objects on the Rows collection, like so:
var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
This is a simple way that works for me and uses lambda expressions:
var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)
Then if you want a particular value:
if(results != null)
var foo = results["ColName"].ToString()
Try this
var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ;
Most likely, the classes for the DataSet, DataTable and DataRow are already defined in the solution. If that's the case you won't need the DataSetExtensions reference.
Ex. DataSet class name-> CustomSet, DataRow class name-> CustomTableRow (with defined columns: RowNo, ...)
var result = from myRow in myDataTable.Rows.OfType<CustomSet.CustomTableRow>()
where myRow.RowNo == 1
select myRow;
Or (as I prefer)
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;
In my application I found that using LINQ to Datasets with the AsEnumerable() extension for DataTable as suggested in the answer was extremely slow. If you're interested in optimizing for speed, use James Newtonking's Json.Net library (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);
Example on how to achieve this provided below:
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();
For VB.NET The code will look like this:
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() ;
Try this...
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 );
}
You can get it work elegant via linq like this:
from prod in TenMostExpensiveProducts().Tables[0].AsEnumerable()
where prod.Field<decimal>("UnitPrice") > 62.500M
select prod
Or like dynamic linq this (AsDynamic is called directly on DataSet):
TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)
I prefer the last approach while is is the most flexible.
P.S.: Don't forget to connect System.Data.DataSetExtensions.dll reference
you can try this, but you must be sure the type of values for each Column
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"),
});
I propose following solution:
DataView view = new DataView(myDataTable);
view.RowFilter = "RowNo = 1";
DataTable results = view.ToTable(true);
Looking at the DataView Documentation, the first thing we can see is this:
Represents a databindable, customized view of a DataTable for sorting, filtering, searching, editing, and navigation.
What I am getting from this is that DataTable is meant to only store data and DataView is there enable us to "query" against the DataTable.
Here is how this works in this particular case:
You try to implement the SQL Statement
SELECT *
FROM myDataTable
WHERE RowNo = 1
in "DataTable language". In C# we would read it like this:
FROM myDataTable
WHERE RowNo = 1
SELECT *
which looks in C# like this:
DataView view = new DataView(myDataTable); //FROM myDataTable
view.RowFilter = "RowNo = 1"; //WHERE RowNo = 1
DataTable results = view.ToTable(true); //SELECT *