How can I make DataTable enumerable? - c#

I cannot use AsEnumerable() on DataTable, I'm using C# 3 but I'm just targeting 2.0 framework (LINQ capability is courtesy of LINQBridge). Is there any way I can make DataTable enumerable without using Select() ?
bool isExisting = (bdsAttachments.DataSource as DataTable).Select().Any(xxx => (string)dr["filename"] == filename);
Update:
I wanted it to make it look like this:
bool isExisting = (bdsAttachments.DataSource as DataTable).AsEnumerable().Any(xxx => (string)dr["filename"] == filename);
I'm getting an inkling that the Select method of DataTable returns a copy, I'm thinking to just use AsEnumerable, the problem is I'm just targeting 2.0 framework, System.Data.DataSetExtensions is not available
BTW, i tried this: http://cs.rthand.com/blogs/blog_with_righthand/archive/2006/01/15/284.aspx, but has compilation errors.

public static IEnumerable<DataRow> EnumerateRows(this DataTable table)
{
foreach (var row in table.Rows)
{
yield return row;
}
}
Allows you to call:
bool isExisting = (bdsAttachments.DataSource as DataTable).EnumerateRows().Any(dr => (string)dr["filename"] == filename);

IEnumerable<DataRow> rows = dataTable.AsEnumerable(); (System.Data.DataSetExtensions.dll)
IEnumerable<DataRow> rows = dataTable.Rows.OfType<DataRow>(); (System.Core.dll)

Keeping your enumerator strictly 2.0:
public static IEnumerable<DataRow> getRows(DataTable table)
{
foreach (DataRow row in table.Rows)
{
yield return row;
}
}
Then call with linqbridge like this:
bool isExisting = getRows(bdsAttachments.DataSource as DataTable).Any(row => (string)row["filename"] == filename);

You can try casting the DataTable as IEnumerable and iterate over the set:
//your data exists as a DataTable
DataTable dt = (DataTable)bdsAttachments.DataSource;
foreach (DataRow row in dt)
{
if (row["filename"] == filename)
return row;
}
The foreach will iterate through the list and search of the filename (I assume you're searching for the first DataRow with that filename, not all rows that match the filename).

Related

Get distinct values from a column of DataTable in .NET 2.0

I am working on a legacy project which was developed using .NET Framework 2.0.
In this project, I get distinct values from DataRowCollection by ItemNo column. I am only interested in ItemNo. The DataRow consist of ItemNo, Qty and Date.
I am thinking of iterating the DataRowCollection and adding the unique ItemNo into a list of string as below (not tested)
var items = new List<string>();
foreach (DataRow orderItem in rows)
{
var itemNo = orderItem["ITEMNO"].ToString().Trim();
if(items.Find(delegate(string str) { return str == itemNo ;}) == null)
{
items.Add(itemNo);
}
}
Is there a better way of doing this without LINQ (.Net Framework 2.0 doesnt like LINQ)
// Given a data table:
var dt = new DataTable();
dt.Columns.Add("ITEMNO");
dt.Rows.Add("1 ");
dt.Rows.Add(" 1");
dt.Rows.Add("2");
var dict = new Dictionary<string, bool>();
foreach(DataRow dr in dt.Rows)
{
var itemNo = dr["ITEMNO"].ToString().Trim();
// Take advantage of O(1) lookup:
if (!dict.ContainsKey(itemNo))
{
dict.Add(itemNo, true);
}
}
// Get list from dictionary keys:
var items = new List<string>(dict.Keys);
If you can install .Net 3.5 on the server, and reference System.Core.dll in your application, you can leverage HashSets which would modify the above code to:
var hashSet = new HashSet<string>();
foreach(DataRow dr in dt.Rows)
{
var itemNo = dr["ITEMNO"].ToString().Trim();
// Only unique elements are added to the hash set,
// no need to check for duplicates
hashSet.Add(itemNo);
}
var items = new List<string>(hashSet);
The benefit of using HashSet over a Dictionary is admittedly trivial, but I'd prefer it since I don't care for the arbitrary bool value in the dictionary, but you'd need to meet the .Net 3.5 and reference requisites.
To get distinct values form a column you can use this method:
List<T> SelectDistict<T>(DataTable table, string column)
{
DataTable temp = new DataView(table).ToTable(true, column);
List<T> items = new List<T>();
foreach (DataRow row in temp.Rows)
items.Add(row.Field<T>(column));
return items;
}
In above method I used DataView.ToTable which by passing true as first argument, selects distinct values.
Here is the usage example:
List<string> items = SelectDistict<string>(yourDataTable, "ITEMNO");
Note
If you need to trim values, you can change above code and first create a clone copy of the DataTable. Then add a computed column which contains, trimmed value from the given column name for distinct values by assigning TRIM(column) to Expression property of column. Then follow the steps using the new trimmed column like above code.

How to find a string in a Column in a DataTable

I am trying to find a fast way to find a string in a Column in a DataTable and add it to a comboBox, and this is the code i tried so far :
adapter = new SqlDataAdapter("Select Id_Editeur ID,Libelle_Editeur Editeur from Editeur", myClass.cnx);
adapter.Fill(myClass.ds, "Editeur");
foreach (String str in myClass.ds.Tables["Editeur"].Columns[1].ToString())
editeurBox.Properties.Items.Add(str);
and that's doesn't work it gives me this error :
foreach statement cannot operate on variables of type
'System.Data.DataColumn' because 'System.Data.DataColumn' does not
contain a public definition for 'GetEnumerator'
How can I do that ? (I don't want the for loop solution).
foreach (var row in myClass.ds.Tables["Editeur"].AsEnumerable())
{
editeurBox.Properties.Items.Add(row[1].ToString());
}
or Full linq-style:
editeurBox.Properties.Items.AddRange(
myClass.ds.Tables["Editeur"]
.AsEnumerable()
.Select(dr => dr[1].ToString()
);
You can try with this code - based on LINQ Field operator
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<string>("RowNo") == "yourSearch"
select myRow;
I think you need to loop through the rows and grab the column that you want. Your code is trying to loop through the column collection which doesn't contain any data:
foreach (DataRow row in myClass.ds.Tables["Editeur"].Rows)
editeurBox.Properties.Items.Add(row[1].ToString());
string TableSelect;
DataTable dt = GetSomeData();
foreach (DataRow row in dt.Rows)
{
TableSelect = "EmplNo = " + row["EmplNo"].ToString();
DataRow[] foundrows;
foundrows = dt.Select(TableSelect);
if (foundrows.Count() > 0)
{
//do something useful here :)
}
}

Which is more efficient, looping through DataTable or more database calls?

Basically I have a DataTable with a rows containing part numbers and a couple of columns that contain information on those parts.
In order to compare those infos with the data we have in the database, I have determined I have one of two options.
Option 1 - Loop through each row and SELECT the data
void CompareData(DataTable dt) {
foreach (DataRow entry in dt.Rows) {
//select that row
DataRow dbEntry = ExecuteQuery("SELECT * FROM Parts WHERE partno='" + entry["partno"] + "'").Rows[0];
if (dbEntry["info1"] == entry["info1"]) {
//do something
} else {
//do something
}
}
}
Option 2 - SELECT all data at once and compare via loops
void CompareData(DataTable dt, string[] parts) {
DataTable dbEntries = ExecuteQuery("SELECT * FROM Parts WHERE partno IN('" + String.Join(parts, "','") + "')");
foreach (DataRow entry in dt.Rows) {
foreach (DataRow dbEntry in dt.Rows) {
if (dbEntry["partno"] == entry["partno"]) {
if (dbEntry["info1"] == entry["info1"]) {
//do something
} else {
//do something
}
}
}
}
}
They both seem pretty inefficient, so I'm not really sure what to do. Would LINQ speed this process up? I've never really used it but just browsing around it looks like something that could help.
Make as few DB calls as possible. You'll be more efficient 99.9% of the time. (general rule to code by)

how to subtract two datatables with linq

Is there any way to subtract two datatables in order to have rows of the first datatable that are not in the second one?
I have tried .Except() method like below but it does not work for me.
dt1.AsEnumerable().Except(dt2.AsEnumerable()).CopyToDataTable();
I think i have mistake in using this method but i could not find that?
You can create your own Comparer using IEquailtyComparer
public class CustomDataRowComparer : IEqualityComparer<DataRow>
{
public bool Equals(DataRow x, DataRow y)
{
for (int i = 0; i < x.Table.Columns.Count; i++)
{
if (x[i].ToString() != y[i].ToString())
{
return false;
}
}
return true;
}
public int GetHashCode(DataRow obj)
{
return obj.ToString().GetHashCode();
}
}
Later you can call it like:
CustomDataRowComparer myDRComparer = new CustomDataRowComparer();
var result2 = dt1.AsEnumerable().Except(dt2.AsEnumerable(),myDRComparer).CopyToDataTable();
Except will not work because the references are different. Each "copy" of a data row in memory is a different object, thus the equality comparison being made in Except will always return false.
You need to compare with something comparable, like row IDs. A couple ideas how to do this:
var rowsInFirstNotInSecond = dt1.Rows.Where(r1=>!dt2.Rows.Any(r2=>r1.ID == r2.ID));
Or:
var rowsInFirstNotInSecond = dt1.Rows.Where(r1=>dt2.FindById(r1.ID) == null);
I have used the following code to subtract two datatables from each other :
var query =
from row1 in dt1
where !(from row2 in dt2
select row2.ID)
.Contains(row1.ID)
select row1;
this code returns exactly what i want...
This Code works for sure:
var rows =dtFirst.AsEnumerable().Except(dtSecond.AsEnumerable(), DataRowComparer.Default);
DataTable result = null;
if (rows.Count() != 0)
result = rows.CopyToDataTable();

Ensure a datatable is ordered by a value

I have a complex algorithm which I am not going to explain here. The code pasted below is doing some processing for each row, but I need to ensure that the table is ordered by a field different than the Primary Key.
I need to do this in this code, not in SQL, or in stored procedures; it needs to be done in .net just before the foreach.
NO LINQ IS ALLOWED, ITS .NET 2.0
THX
Your help is appreciated.
List<int> distinctREFMDossierIds = GetREFMDossierIdsFromBookings();
foreach (int refmDossierId in distinctREFMDossierIds)
{
bool errorsFoundInDetails = false;
bool errorsFoundInHeaders = false;
wingsBookingInterfaceIdswithErrors.Clear();
dicRows.Clear();
sbWingsBookingInterfaceIds= new StringBuilder();
YBooking booking = new YBooking();
foreach (UC090_WingsIntegrationDataSet.WingsBookingInterfaceRow row in _uc090_WingsIntegrationDataSet.WingsBookingInterface.Rows)
{
//code
}
You can use LINQ:
foreach(var row in _uc090_WingsIntegrationDataSet.WingsBookingInterface
.OrderBy(r => r. Something))
You can sort a DataTable like this:
DataTable dt = new DataTable();
dt.DefaultView.Sort = <Sort expression>;
dt = dt.DefaultView.ToTable();
WingsBookingInterface.Rows.OrderBy(item => item.columnName);
You can sort a collection ( for example a List<> ) with the OrderBy extension method.

Categories

Resources