I iterate a DataTable's rows using -
DataTable dt = getDataTableFromSomeWhere();
DataRow row = null;
//for loop
row = dt.Rows[i];
How do I get the value of a column of the i-th row, by using the name of the column ?
I can iterate the columns using dt.Columns[j], but thats not what I want.
Just use the indexer taking a string parameter:
object value = row["ColumnName"];
EDIT: Assuming the value has been fetched in an appropriate type, I'd normally just cast to the CLR type you want:
int someIntegerValue = (int) row["ColumnName"];
Sometimes you may need two levels of casting (one to unbox and then another to perform an actual value conversion) but it depends on what you need.
I would recommend against converting to a string representation and then parsing that, unless you've really got no alternative. Excessive string conversions not only harm performance (usually not relevant) but they lead to sloppy type choices.
string name = (string) row["ColumnName"];
or
int i = Convert.ToInt32( row["ColumnName"]);
referencing by name is tiny bit slower but way more readable.
Related
I have a dataset with one datatable, one row and six columns:
DataSet holdall = new DataSet();
holdone.Fill(holdall);
DataTable invoiceTable = holdall.Tables["INVOICE"];
The data comes from an SQL database, and consists of several different data types. I need to pass this data into an array or a list (AFAIK An array is more appropriate), and on the way convert it into string format:
string[] currentInvoice = new string[6];
currentInvoice = invoiceTable.AsEnumerable().Take(1).ToString().ToArray();
This gives me the following error:
Cannot implicitly convert type 'char[]' to 'string[]'
I have also tried
foreach (DataRow INVOICE in invoiceTable.AsEnumerable())
{
currentInvoice.ToArray();
}
However, this returns a Null exception, that leads be to believe that there is no data in the datatable. Upon examining the datatable via a stop point, I find that there is the correct amount of data.
Am I overcomplicating this?
When you call .ToString() you're converting whatever that is to a single string. Calling .ToArray() on a single string doesn't split that string into any meaningful substrings, it just converts it to a char[], which as the error states is incompatible with the variable type string[].
So, if I understand correctly... You have a table, of which you want only the first row, and you want the items in that row to be strings in an array? Something like this ought to work:
currentInvoice = invoiceTable.AsEnumerable().First().ItemArray.Select(i => i.ToString()).ToArray();
It takes the table as an enumerable, grabs the first row, looks at the array of items in that row, converts each item to a string, and converts that enumeration of strings into an array.
Edit: Note the use of .First() instead of .Take(1). While conceptually they do the same thing, .Take() returns a collection of items (even if there's only one item in the collection) whereas .First() returns only a single item. Note also that these could throw errors if there are no items in the collection from which you try to extract the first element. So you might want to add some error checking to ensure the table has rows before trying to extract the first row, if there could be a situation where it doesn't have rows.
In C#, which one is more efficient way of reading reader object, through integer indexes or through named indexes ?
ad.Name = reader.GetString(0);
OR
ad.Name = reader["Name"].ToString();
The name overload needs to find the index first.
MSDN
a case-sensitive lookup is performed first. If it fails, a second
case-insensitive search is made (a case-insensitive comparison is done
using the database collation). Unexpected results can occur when
comparisons are affected by culture-specific casing rules. For
example, in Turkish, the following example yields the wrong results
because the file system in Turkish does not use linguistic casing
rules for the letter 'i' in "file".
From Getordinal (which is used therefore):
Because ordinal-based lookups are more efficient than named lookups,
it is inefficient to call GetOrdinal within a loop. Save time by
calling GetOrdinal once and assigning the results to an integer
variable for use within the loop.
so in a loop it might be more efficient to lookup the ordinal index once and reuse that in the loop body.
However, the name-lookup is backed by a class that is using a HashTable which is very efficient.
reader.GetString(index);
This will get the row value at that column index as string, The second solution is more ideal because it allows you to get the value at that index in your own prefered type.
Example:-
String name = reader["Name"].ToString();
int age = (int) reader["Age"]
ad.Name = reader["Name"].ToString();
This is most efficient way.
Because although you change database table structure afterwords, there will be no effect on this code since you have directly mentioned column name.
But with column index, it will change when you add any column to table before this column.
I have my query as below
DataRow dr = objDtModifier.Rows[num];
var existingRows = resultDataTable.AsEnumerable().Where(row => row == dr);
But existingRows.Count always returns me zero .
Can anyone tell what's wrong here .
You are comparing a row object from the objDtModifier source colloction with a different set of row objects in a resultDataTable collection which will alway return an empty result set as they are a different set of object references (this is regardless of whether they contain the same data or not).
Is there a property you can test against? eg:
var existingRows = resultDataTable.AsEnumerable().Where(row => row.Id == dr.Id);
It happens because row and dr not same object and your are going to compare two object,
try to check columns of row , something like primary keyvalue
You compare a row object which you get from a table called objDtModifier against a row from a table called resultDataTable. So unless that's a typo this is probably what's wrong.
Edit: Even if they contain rows from the same database table you are comparing the object references of two different row objects - this will fail. You need to compare two columns which uniquely identify the row (or maybe a set of columns).
No matter if they are same type. If objDtModifier and resultDataTable does not contain same instances the behaviour you get is correct.
row==dr uses equality by reference, like chris stated. if objDtModifier and resultDataTable contains diffrent row instances but refers to same data, you might want to use row.id==dr.id if id is the primary key of the datable.
I am working with SqlXml and the stored procedure that returns a xml rather than raw data. How does one actually read the data when returned is a xml and does not know about the column names. I used the below versions and have heard getting data from SqlDataReader through ordinal is faster than through column name. Please advice on which is best and with a valid reason or proof
sqlDataReaderInstance.GetString(0);
sqlDataReaderInstance[0];
and have heard getting data from SqlDataReader through ordinal is faster than through column name
Both your examples are getting data through the index (ordinal), not the column name:
Getting data through the column name:
while(reader.Read())
{
...
var value = reader["MyColumnName"];
...
}
is potentially slower than getting data through the index:
int myColumnIndex = reader.GetOrdinal("MyColumnName");
while(reader.Read())
{
...
var value = reader[myColumnIndex];
...
}
because the first example must repeatedly find the index corresponding to "MyColumnName". If you have a very large number of rows, the difference might even be noticeable.
In most situations the difference won't be noticeable, so favour readability.
UPDATE
If you are really concerned about performance, an alternative to using ordinals is to use the DbEnumerator class as follows:
foreach(IDataRecord record in new DbEnumerator(reader))
{
...
var value = record["MyColumnName"];
...
}
The DbEnumerator class reads the schema once, and maintains an internal HashTable that maps column names to ordinals, which can improve performance.
Compared to the speed of getting data from disk both will be effectively as fast as each other.
The two calls aren't equivalent: the version with an indexer returns an object, whereas GetString() converts the object to a string, throwing an exception if this isn't possible (i.e. the column is DBNull).
So although GetString() might be slightly slower, you'll be casting to a string anyway when you use it.
Given all the above I'd use GetString().
Indexer method is faster because it returns data in native format and uses ordinal.
Have a look at these threads:
Maximize Performance with SqlDataReader
.NET SqlDataReader Item[] vs. GetString(GetOrdinal())?
This was originally a problem with Crystal Reports but I tracked down the issue to a single line of code:
foreach (DataRow dr in ds.Tables["CurrentScheduleFields"].Rows)
if (dr["MY_FIELD"].ToString() == string.Empty)
dr["MY_FIELD"] = 0;
I am using an Oracle database. The field is actually a Numeric(2). We are using straight ADO.NET and no Nullable types in this case. In one case, the field in question has a value of an int and the above line of code is fine. The other case, the value of the field is DBNull.Value, and the above or something is converting the 0 to "0" ( a string).
dr is not a `DataReader foreach (DataRow dr in ds.Tables["CurrentScheduleFields"].Rows)
Does anyone know why?
My browser is not letting me click on the Add Comments, so I am adding stuff here. Why can't I do if (dr["MY_FIELD"] == DBNull.Value)
dr["MY_FIELD"] = 0;
the debugger hits that and converts to a string with a value of "0", not 0. I guess the first answer handles this, "So the problem may be that the first "MY_FIELD" is null, convincing ADO.NET that the type for that column is a string." So it's now string with DBNull.Value in it?
My browser is locked down. I can't click on anything except edit this but:
ANSWER: Handle this on the Crystal side by changing the formula to handle a string for this value and not an int. It works!
In some cases, when dealing with DataTable, I've seen it try to "guess" at the type of a column based on the value in that column in the first row in your set. So the problem may be that the first "MY_FIELD" is null, convincing ADO.NET that the type for that column is a string.
You may want to set the schema for your DataTable before you try to load it.