I have a datatable and we fetch values from one database, put them in a datatable and insert them into another database. I am using the execute query method of sql and stored procedures to insert data. If one row has a string or binary data truncated error can we identify this using c# and printing that row on console??
Basically, everything is fine in dt but when I insert it I will get exception. Can I get the detail row which is causing exception?
Can anyone guide me on how to proceed with this? I need to know the exact row which is causing the issue.
If you don't know which specific row is causing the error, you'll probably have to foreach loop through it.
foreach(DataRow row in yourDataTable.Rows) {
//Check for the issue.
}
This will loop through each DataRow in your table. You'll have to check each individual cell, but you can't foreach loop through it, you'll have to do it manually based on the row. For example, if you know each Column name, you can do:
if(row["whatever"]...) // you want to check for the issue here.
You can also do:
int len = yourDataTable.Columns.Count;
foreach(DataRow row in yourDataTable.Rows) {
for(int i = 0; i < len; i++) {
//Check based in row[i] for your problem.
}
}
That will loop through each row, then each cell in each row based on index. You'll have to do your comparison based on the type received, though, which you'll have to determine based on the contents of your DataTable.
Related
I have a DataTable object that I need to fill based on data stored in a stream of columns - i.e. the stream initially contains the schema of the DataTable, and subsequently, values that should go into it organised by column.
At present, I'm taking the rather naive approach of
Create enough empty rows to hold all data values.
Fill those rows per cell.
The result is a per-cell iteration, which is not especially quick to say the least.
That is:
// Create rows first...
// Then populate...
foreach (var col in table.Columns.Cast<DataColumn>)
{
List<object> values = GetValuesfromStream(theStream);
// Actual method has some DBNull checking here, but should
// be immaterial to any solution.
for (var i=0; i<values.Count; i++)
table.Rows[i][col] = values[i];
}
My guess is the backing DataStorage items for each column aren't expanding as the rows are added, but as values are added to each column, but I'm far from certain. Any tips for loading this kind of data.
NB that loading all lists first and then reading in by row is probably not sensible - this approach is being taken in the first place to mitigate potential out of memory exceptions that tend to result when serializing huge DataTable objects, so grabbing a clone of the entire data grid and reading it in would probably just move the problem elsewhere. There's definitely enough memory for the original table and another column of values, but there probably isn't for two copies of the DataTable.
Whilst I haven't found a way to avoid iterating cells, as per the comments above, I've found that writing to DataRow items that have already been added to the table turns out to be a bad idea, and was responsible for the vast majority of the slowdown I observed.
The final approach I used ended up looking something like this:
List<DataRow> rows = null;
// Start population...
var cols = table.Columns.Cast<DataColumn>.Where(c => string.IsNullOrEmpty(c.Expression));
foreach (var col in cols)
{
List<object> values = GetValuesfromStream(theStream);
// Create rows first if required.
if (rows == null)
{
rows = new List<DataRow>();
for (var i=0; i<values.Count; i++)
rows.Add(table.NewRow());
}
// Actual method has some DBNull checking here, but should
// be immaterial to any solution.
for (var i=0; i<values.Count; i++)
rows[i][col] = values[i];
}
rows.ForEach(r => table.Rows.Add(r));
This approach addresses two problems:
If you try to add an empty DataRow to a table that has null-restrictions or similar, then you'll get an error. This approach ensures all the data is there before it's added, which should address most such issues (although I haven't had need to check how it works with auto-incrementing PK columns).
Where expressions are involved, these are evaluated when row state changes for a row that has been added to a table. Consequently, where before I had re-calculation of all expressions taking place every time a value was added to a cell (expensive and pointless), now all calculation takes place just once after all base data has been added.
There may of course be other complications with writing to a table that I've not yet encountered because the tables I am making use of don't use those features of the DataTable class/model. But for simple cases, this works well.
In a Winforms application I have to log all changes in datagrid (datatable). In other words I want to to get all changes, since it has been loaded. For this I want to use Datatable.GetChanges(). I know, that with GetChanges() I get a datatable containing a copy of all rows in the original DataSet that have pending changes.
My question is now, if it is also possible to get more additional information of the changes. For example I want to know if a row has been added or deleted or only has been updated. If a row has been updated I also want to know which cells has been updated? Is there a way to get all this information quickly or does I have to do a deep comparison row by row with the original datatable?
Or is it better to use RowState to get all changes?
For the row addition/deletion check RowState
For each item in the row (aka the cell) check DataRowVersion
foreach (DataRow dr in dt.Rows)
{
if (dr.RowState == DataRowState.Modified)
{
var changedCols = new List<DataColumn>();
foreach (DataColumn dc in dt.Columns)
{
if (!dr[dc, DataRowVersion.Original].Equals(
dr[dc, DataRowVersion.Current])) /* skipped Proposed as indicated by a commenter */
{
changedCols.Add(dc);
}
}
// now handle the changedCols list
}
}
Each DataRow in the resulting DataTable will have its RowState property set, which tells you whether the row was added, deleted, or updated.
I do not believe individual cells provide update information, however - it's only tracked by row.
I think this problem is related to Reference Types, and my lack of understanding of these ...
So I have dynamically created ASP.Net Tables (as in Web.UI.WebControls.Table, not the database variety)
These can have anything from one row with one cell with text, to a whole series of nested tables and controls, depending on the clients.
I need to loop through each TableRow, if a certain condition is met then I copy that row to a 2nd Table object. Here's a simplified bit of the code.
Table xTblComplete = (passed in as parameter) // original & complete table
Table xTblTemp = new Table(); // gets built dynamically with specific rows
foreach (TableRow xThisRow in xTblComplete.Rows)
{
if (xThisRow.Cells.Count > 0)
{
if (certain condition met)
{
xTblTemp.Rows.Add(xThisRow);
}
}
}
Where I come unstuck is that the foreach (row in table.rows) throws an error when I try to add the TableRow to Table2. I get the error "Collection was modified; enumeration operation may not execute. "
This makes sense, in that I should be making a COPY of that Table Row to add.
Can anyone advise on how this is done? I've scanned MSDN and the forums for general copying-of-reference types, but they all seem to point to using ICloneable , which I believe I'm unable to do as this isn't my class.
Am hoping this is something small and fundamental I'm missing out on, thanks in advance.
You are iterating through the row collection using the for loop. You can't modify the collection while doing that, that's why you are getting the error message. That row is attached to that table. Period.
If you need a copy of that row get the values you are looking for cell by cell. Here is an example:
TableRow tempRow= new TableRow();
Table xTblTemp= new Table();
for (int i = 0; i < xTblComplete.Rows[0].Cells.Count - 1; i++)
{
TableCell cell = xTblComplete.Rows[0].Cells[i];
tempRow.Cells[i].Text = cell.Text;
}
xTblTemp.Rows.Add(tempRow);
Thanks Ulises, your answers were helpful, unfortunately the complexity of these tables procluded a simple loop & copy contents. By that I mean that there were cells that might possibly have had 5 levels of nested tables, with any number of web controls inside each. Yep, a CSS perfectionist would retch at the idea of so many nested tables, but it's what had to be done!!
In the end I utilized a while(bln) loop, examining xTblComplete.Rows[0] each time.
If it met the condition , I would copy it to xTmpTable, which also removed it from xTblComplete.
If it failed the condition, I would remove it myself ( xTblComplete.Rows.Remove(xTblComplete.Rows[0]);
This way Rows[0] would always be the next to process.
After each Loop I checked the bln for more rows to process, if none then the loop would exit.
I've read a lot of where people have missing cell data due to null values but my issue is I have spreadsheets I'm parsing that have exactly 272 rows of data needing to be parsed. When I get the row count I'm only able to retrieve 269. Below is how I'm getting the row count.
// code above gets worksheet...
var rows = from row in worksheet.Descendants<Row>()
where row.RowIndex >= rowIndex
select row;
for (int i = 0; i <= rows.Count(); i++)
{
// processing...
}
The rowIndex above is used because I'm only pulling 272 rows after a few heading rows and it needs to be dynamic as some sheets have multiple heading rows. Basically I search for a particular cell value for a string and then from there get the rowIndex and use that to get the row count.
I've tracked down the two rows not being picked up and do not have values in them, but there are other rows exactly the same that do not have values and the rows are included. It is important as all sheets I need to parse have 272 rows of specific data with blank rows in the same spot. One sheet will work fine and include the rows while another won't.
So I'm trying to determine why some blank rows are included but others are totally ignored like they do not exist.
Any help would be appreciated.
The rows that don't have cells that have values should not be included as a rows in the total count. This makes sense since excel does not store row or cell information where the cell value is null.
The other rows that don't have any values in them but do show up most likely have a space in a cell somewhere. A space is a valid value for a cell and while it looks empty, it will be stored as a cell value and count towards the total number of rows.
This is my first post on Stackoverflow.
I am reading millions of rows from a flat file (comma delimited) and iterating each read row and then each column of each row. The iteration of each column is to allow user defined conversions, defaults, removal of special characters, etc. to be performed. The current implementation is very efficient.
The reading of the data is done in batches of 20k. When I'm processing a read row, I issue a NewRow() call on my in-memory DataTable. I then start iterating each column to scrub their values. I'm trying to minimize as much as I can when I'm processing a rows columns.
My problem is this. If the value (text in this case) that is read from the flat file is longer than the MaxLength of the targeted DataTables DataColumn, I receive an exception stating such when I issue the following:
dataTable.Rows.Add(newRow);
Is there a way to tell ADO.Net (or my in-memory DataTable) to truncate the data instead of complaining?
Again, I can easily add logic in the loop to do this check/truncation for me, but those things add up when you're dealing with millions of rows of data.
something like this should work:
var newRow = dataTable.NewRow();
...
...
if(YourText.Length < ColumnMaxLength)
{
newRow["YourLimitedColumnName"] = YourText;
}
else
{
newRow["YourLimitedColumnName"] = YourText.Substring(0, ColumnMaxLength);
}
...
...
dataTable.Rows.Add(newRow);