I am using C# 2.0, and I can't help but think this isn't the most efficient way to search a collection (in this case a DataTable) for a value:
bool found = false;
foreach (DataRow row in data.Rows)
{
if (id == row["rowID"])
{
found = true;
break;
}
}
if (!found)
{
//Do stuff here
}
Can anyone think of a "cleaner" way to do this?
Look at the datatable's Select() method:
http://msdn.microsoft.com/en-us/library/b5c0xc84(VS.80).aspx
DataRow[] rows = data.Select("rowID=" + id.ToString());
if (rows.Length > 0)
{
//Do stuff here
}
This is a linear search and it is the slowest actual search there is.
One alternative, if you want to continue using a DataTable, is to define a primary key and use the Find() method:
myTable.PrimaryKey = new DataColumn[] { new DataColumn("rowID") };
DataRow row = myTable.Find(id);
Related
DataTable checkbag=(DataTable)Session["bag"];
foreach(DataRow row in checkbag.Rows)
{
if(row["id"].ToString()==e.CommandArgument.ToString()
{
Response.Redirect("mybag.aspx");
break;
}
}
I usually use this. Not sure if answer will be different
foreach(DataRow row in checkbag.AsEnumerable())
{
if(row.Field<string>("id") == e.CommandArgument.ToString())
{
Response.Redirect("mybag.aspx");
break;
}
}
I'm trying to figure out if my data table contains a certain row. So I used the .Contains method, but when I tried to run my program I was met with a MissingPrimaryKeyException which I can't figure out.
DataTable table = dataQuery.executeQuery();
foreach(DataRow row in table.Rows)
{
if(table.Rows.Contains("certainRow"))
{
blah blah blah
...
I am only getting the exception the 2nd time I call table.Rows which is what is making no sense to me. If my table didn't have a primary key, wouldn't it have given me an error in the foreach call?
EDIT: I just realized that Contains did something else than I thought it did. Matthijs... yes that is kind of what I want. I need to know if "certainRow" is actually a row that exists otherwise I cannot manipulate the data in that row.
Unfortunately I am new to C# and haven't programmed in anything in over 5years so I cannot figure out if there is a method that does what I want. Or if I need to create something myself.
EDIT#2:
I figured out a solution to my problem using the DataTableReader.
private bool doesExist(string rowName, DataTable table)
{
bool value = false;
DataTableReader reader = new DataTableReader(table);
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if (reader.GetValue(i) == rowName)
{
value = true;
}
}
}
return value;
}
You should be able to use the DataTableReader, more information can be found here.
An example, would be:
private static DataTable GetCustomer()
{
DataTable table = new DataTable();
DataColumn id = table.Columns.Add(#"Id", typeof(int));
table.Columns.Add(#"Name", typeof(string));
table.PrimaryKey = new DataColumn[] { id };
table.Rows.Add(new object[] { 1, #"John" });
return table;
}
The above code will build a table, as you see you define your Primary Key and add the Content. That is how you would build the table. Now to read, you would:
using(DataTableReader reader = new DataTableReader(new DataTable[] { customer }))
{
do
{
if(reader.HasRows)
{
// Do Something
}
} while (reader.NextResult());
}
As you can see it validates the row exist, then performs a task. Very simple example, hope it helps.
The .Contains will return a boolean for a true or false value.
In regards to your comment, you can call reader[#"ColumnName"] and it should attempt to read it without an issue. So if:
if(reader[#"ColumnName"] != DBNull.Value)
{
// Do Something.
}
You could just write:
bool contains = table.Rows.Cast<DataRow>().SelectMany(r => r.ItemArray).Contains(value);
At the moment, when I iterate over the DataRow instances, I do this.
foreach(DataRow row in table)
return yield new Thingy { Name = row["hazaa"] };
Sooner of later (i.e. sooner), I'll get the table to be missing the column donkey and the poo will hit the fan. After some extensive googling (about 30 seconds) I discovered the following protection syntax.
foreach(DataRow row in table)
if(row.Table.Columns.Contains("donkey"))
return yield new Thingy { Name = row["hazaa"] };
else
return null;
Now - is this the simplest syntax?! Really? I was expecting a method that gets me the field if it exists or null otherwise. Or at least a Contains method directly on the row.
Am I missing something? I'll be mapping in many fields that way so the code will look dreadfully unreadable...
You can create an extension method to make it cleaner:
static class DataRowExtensions
{
public static object GetValue(this DataRow row, string column)
{
return row.Table.Columns.Contains(column) ? row[column] : null;
}
}
Now call it like below:
foreach(DataRow row in table)
return yield new Thingy { Name = row.GetValue("hazaa") };
As your DataTable table always has the same columns ( they won`t change for any row ) you only need to check for the columnname once.
if (table.Columns.Contains("donkey"))
{
foreach ...
}
I really liked the approach taken by #Varun K. So, having that as a departing point I just wanted to put my two cents, in case it helps someone else. I simply improved it making it generic instead of just using object as a return type.
static class Extensions
{
public static T Get<T>(this DataRow self, string column)
{
return self.Table.Columns.Contains(column)
? (T)self[column]
: default(T);
}
}
}
To build on the answer by Varun K, use a generic type parameter:
public static T GetValue<T>(this DataRow row, string column)
{
if (!row.Table.Columns.Contains(column))
return default(T);
object value = row[ColumnName];
if (value == DBNull.Value)
return default(T);
return (T)value;
}
foreach (DataColumn item in row.Table.Columns)
{
switch (item.ColumnName)
{
case "ID":
{
p.ID = Convert.ToInt32(row[item.ColumnName].ToString());
}
break;
case "firstName":
{
p.firstName = row[item.ColumnName].ToString();
}
break;
case "lastName":
{
p.lastName = row[item.ColumnName].ToString();
}
break;
default:
break;
};
}
Sometimes a column name might exist, but a row does not contain the data for that column; for example, after filling DataTable using ReadXML.
A simple, fast and secure solution would be to use type checking:
if(row["columnname"].GetType() != typeof(System.DBNull)){
//DataRow contains "columname"
}else{
//a safe scope to set default cell data
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Foreach loop, determine which is the last iteration of the loop
foreach (DataRowView row in orderedTable.DefaultView)
{
if(lasttime) do-something;
}
orderedtable is a datatable
does anyone know how to find out whether we are on the last foreach iteration? please keep in mind that i do have duplicates in orderedtable
The correct method that works in all cases is to use the IEnumerator<T> directly:
using (var enumerator = orderedTable.DefaultView.GetEnumerator())
{
if (enumerator.MoveNext())
{
bool isLast;
do
{
var current = enumerator.Current;
isLast = !enumerator.MoveNext();
//Do stuff here
} while (!isLast);
}
}
This method works even if your collection doesn't have a Count property, and even if it does, this method will be more efficient if the Count property is slow.
The foreach construct does not know such a thing, since it applies equally to unbounded lists. It just has no way of knowing what is a last item.
You can iterate the manual way as well, though:
for (int i = 0; i < orderedTable.DefaultView.Count; i++) {
DataRowView row = orderedTable.DefaultView[i];
if (i == orderedTable.DefaulView.Count - 1) {
// dosomething
}
}
An alternative approach which I don't think anyone posted. This works well if you don't know the count ahead of time.
DataRowView lastRow;
foreach (DataRowView row in orderedTable.DefaultView)
{
// Do something...
lastRow = row;
}
if (lastRow != null)
{
// Do something with last row
}
You will have to use a regular for loop if you want to have different behavior on the last item.
for (int i = 0; i < orderedTable.DefaultView.Count; i++)
{
//do stuff
if (i == orderedTable.DefaultView.Count - 1)
{
//do additional special stuff
}
}
It's worth noting that "the other Skeet" has an implementation for a "smart enumerable" which supports a Last property. See the article here: http://msmvps.com/blogs/jon_skeet/archive/2007/07/27/smart-enumerations.aspx
With this you could write something like this (I might get the details wrong, haven't tried it out myself):
foreach (SmartEnumerable<DataRowView> item in new SmartEnumerable<DataRowView>(orderedTable.DefaultView))
{
DataRowView row = item.Value;
if(item.IsLast)
{
///do special stuff
}
}
Instead of using foreach get the IEnumerator. If MoveNext returns null the previous was the last one.
for would work too of course.
You could possibly do something like the following:
foreach (DataRowView row in orderedTable.DefaultView)
{
if(row == orderedTable.DefaultView.Last()) do-something;
}
But its pretty inefficient.
If you're concerned in keeping track of your iteration, why not use a for instead or a foreach? Then you can simply do the following:
for(int i = 0; i<orderedTable.DefaultView.Count-1;i++)
{
if(i==orderedTable.DefaultView.Count-1)
{
// Last Row
}
}
The code you have posted is identical to:
if (orderedTable.DefaultView.Rows.Count > 0)
do-something;
If that does not do what you want, you will have to explain what lastTime does.
If I understand your question, does this help?
int lastrow = 0;
foreach (DataRow row in table.Rows) // Loop over the rows.
{
lastrow++;
// Do Something
if (lastrow == (table.Rows.Count - 1))
{
// Do something else
}
}
I got this:
DataTable dtEntity = CreateDataTable();
drEntity = dtEntity.NewRow();
Then I add data to the row (or not).
Lots of code, really don't know if there's anything inside the row.
Depends on the input (i am importing from some files).
I'd like to do something like:
if (drEntity`s EVERY CELL IS NOT EMPTY)
{
dtEntity.Rows.Add(drEntity);
}
else
{
//don't add, will create a new one (drEntity = dtEntity.NewRow();)
}
Is there some nice way to check if the DataRow's every cell is empty?
Or I should foreach, and check them one by one?
A simple method along the lines of:
bool AreAllColumnsEmpty(DataRow dr)
{
if (dr == null)
{
return true;
}
else
{
foreach(var value in dr.ItemArray)
{
if (value != null)
{
return false;
}
}
return true;
}
}
Should give you what you're after, and to make it "nice" (as there's nothing as far as I'm aware, in the Framework), you could wrap it up as an extension method, and then your resultant code would be:
if (datarow.AreAllColumnsEmpty())
{
}
else
{
}
I created an extension method (gosh I wish Java had these) called IsEmpty as follows:
public static bool IsEmpty(this DataRow row)
{
return row == null || row.ItemArray.All(i => i is DBNull);
}
The other answers here are correct. I just felt mine lent brevity in its succinct use of Linq to Objects. BTW, this is really useful in conjunction with Excel parsing since users may tack on a row down the page (thousands of lines) with no regard to how that affects parsing the data.
In the same class, I put any other helpers I found useful, like parsers so that if the field contains text that you know should be a number, you can parse it fluently. Minor pro tip for anyone new to the idea. (Anyone at SO, really? Nah!)
With that in mind, here is an enhanced version:
public static bool IsEmpty(this DataRow row)
{
return row == null || row.ItemArray.All(i => i.IsNullEquivalent());
}
public static bool IsNullEquivalent(this object value)
{
return value == null
|| value is DBNull
|| string.IsNullOrWhiteSpace(value.ToString());
}
Now you have another useful helper, IsNullEquivalent which can be used in this context and any other, too. You could extend this to include things like "n/a" or "TBD" if you know that your data has placeholders like that.
I prefer approach of Tommy Carlier, but with a little change.
foreach (DataColumn column in row.Table.Columns)
if (!row.IsNull(column))
return false;
return true;
I suppose this approach looks more simple and cleaner.
public static bool AreAllCellsEmpty(DataRow row)
{
if (row == null) throw new ArgumentNullException("row");
for (int i = row.Table.Columns.Count - 1; i >= 0; i--)
if (!row.IsNull(i))
return false;
return true;
}
I know this has been answered already and it's an old question, but here's an extension method to do the same:
public static class DataExtensions
{
public static bool AreAllCellsEmpty(this DataRow row)
{
var itemArray = row.ItemArray;
if(itemArray==null)
return true;
return itemArray.All(x => string.IsNullOrWhiteSpace(x.ToString()));
}
}
And you use it like so:
if (dr.AreAllCellsEmpty())
// etc
You could use this:
if(drEntity.ItemArray.Where(c => IsNotEmpty(c)).ToArray().Length == 0)
{
// Row is empty
}
IsNotEmpty(cell) would be your own implementation, checking whether the data is null or empty, based on what type of data is in the cell. If it's a simple string, it could end up looking something like this:
if(drEntity.ItemArray.Where(c => c != null && !c.Equals("")).ToArray().Length == 0)
{
// Row is empty
}
else
{
// Row is not empty
}
Still, it essentially checks each cell for emptiness, and lets you know whether all cells in the row are empty.
DataTable.NewRow will initialize each field to:
the default value for each DataColumn (DataColumn.DefaultValue)
except for auto-increment columns (DataColumn.AutoIncrement == true), which will be initialized to the next auto-increment value.
and expression columns (DataColumn.Expression.Length > 0) are also a special case; the default value will depend on the default values of columns on which the expression is calculated.
So you should probably be checking something like:
bool isDirty = false;
for (int i=0; i<table.Columns.Count; i++)
{
if (table.Columns[i].Expression.Length > 0) continue;
if (table.Columns[i].AutoIncrement) continue;
if (row[i] != table.Columns[i].DefaultValue) isDirty = true;
}
I'll leave the LINQ version as an exercise :)
AFAIK, there is no method that does this in the framework. Even if there was support for something like this in the framework, it would essentially be doing the same thing. And that would be looking at each cell in the DataRow to see if it is empty.
I did it like this:
var listOfRows = new List<DataRow>();
foreach (var row in resultTable.Rows.Cast<DataRow>())
{
var isEmpty = row.ItemArray.All(x => x == null || (x!= null && string.IsNullOrWhiteSpace(x.ToString())));
if (!isEmpty)
{
listOfRows.Add(row);
}
}
Maybe a better solution would be to add an extra column that is automatically set to 1 on each row. As soon as there is an element that is not null change it to a 0.
then
If(drEntitity.rows[i].coulmn[8] = 1)
{
dtEntity.Rows.Add(drEntity);
}
else
{
//don't add, will create a new one (drEntity = dtEntity.NewRow();)
}
To delete null and also empty entries Try this
foreach (var column in drEntitity.Columns.Cast<DataColumn>().ToArray())
{
if (drEntitity.AsEnumerable().All(dr => dr.IsNull(column) | string.IsNullOrEmpty( dr[column].ToString())))
drEntitity.Columns.Remove(column);
}