I am reading my DataTable as follow:
foreach ( DataRow o_DataRow in vco_DataTable.Rows )
{
//Insert More Here
}
It crash; because I insert more records.
How can I read my DataTable without reading the new records? Can I read by RowState?
Thanks
Since I don't know what language you are using I can only give general advice.
In most (all?) languages it's not possible to do a foreach over a collection if you are modifying the collection. There are two common ways to deal with this.
Wild ass guessing pseudo code follows:
// first way uses array notation (if possible)
var no_of_rows = vco_DataTable.Rows.count();
for(var i = 0; i < no_of_rows; i++) {
DataRow o_DataRow = vco_DataTable.Rows[i];
//Insert More Here
}
// The second way copies the data
var my_copy = vco_DataTable.Copy()
foreach ( DataRow o_DataRow in my_copy.Rows )
{
//Insert More into vco_DataTable Here
}
copy.Dispose() // delete/destroy the copy
Related
I want to know if someone of you know a faster way to fill a DataTable manually then I do.
Here is what I got, I have a List with about 1.7b entries.
I want to fill this entries as fast as possible into DataTable with one column.
An entry in my list looks like this here {"A2C","DDF","ER","SQ","8G"}
My code need about 7-8 seconds
for (int i = 0; i <= lists.Count; i++)
{
table_list.Rows.Add();
}
for (int a = 0; a < list.Count; a++)
{
table_list.Rows[a][0] = list[a][0] + list[a][1] +
list[a][2] + list[a][3] + list[a][4];
}
As I didn't find any similar question on the board (just questions about how to fill datatable by sql and fill method), I decided to post my question.
Any input is highly appreciated!
i add this DataTable into an sql server database (i do this by SqlBulkCopy)
This is a mistake; the DataTable is pure overhead here. What you should expose is an IDataReader over that data. This API is a bit tricky, but FastMember makes it easier. For example, it sounds like you have 1 column; so consider:
class Foo {
public string ColumnName {get;set;}
}
Now write an iterator block method that converts this from the original list per item:
IEnumerable<Foo> Convert(List<TheOldType> list) {
foreach(var row in list) {
yield return new Foo { ColumnName = /* TODO */ };
}
}
and now create an IDataReader via FastMember on top of that lazy sequence:
List<TheOldType> list
var data = Convert(list);
using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(data, "ColumnName"))
{
bcp.DestinationTableName = "SomeTable";
bcp.WriteToServer(reader);
}
This works much better than populating a DataTable - in particular, it avoids populating a huge DataTable. Emphasis: the above is spooling - not buffered.
Why do you create an empty row first, then loop the table again to fill them?
I would use a simple foreach:
var table_list = new DataTable();
table_list.Columns.Add();
foreach(string[] fields in lists)
{
DataRow newRow = table_list.Rows.Add();
newRow.SetField(0, string.Join("", fields));
}
Why do you put all into one field?
Why not use the LoadDataRow method of the DataTable.
// turnoff notifications
table_list.BeginLoadData();
// load each row into the table
foreach(string[] fields in lists)
table_list.LoadDataRow(new object[] { string.Join("", fields) }, false);
// turn notifications back on
table_list.EndLoadData();
Also see: DataTable.LoadDataRow Method http://msdn.microsoft.com/en-us/library/kcy03ww2(v=vs.110).aspx
I'm trying to transfer my datatable contents to another array. I am only going to get specific fields from the datatable, but I do not know how to save the specific columns content to another array.
What I did:
dr = SuperViewBLL.GetSomeStuff();
string[] new_array;
if (dr.Rows.Count > 0)
{
for (int i = 0; i < dr.Rows.Count;i++ )
{
new_array[i] = dr.Rows[i]['StuffLocationId'];
// I do know this is wrong
}
}
How can I get the column StuffLocationId to the array new_array?
That line is almost right, except that you need double quotes rather than single and you also need to cast/convert the value to type String to put it into a String array:
new_array[i] = (string) dr.Rows[i]["StuffLocationId"];
or, if the data is nullable:
new_array[i] = dr.Rows[i]["StuffLocationId"] as string;
The issue is that the array doesn't exist because you haven't created it. In order to create an array you have to know the size. If you haven't specified a size, either implicitly or explicitly, then you haven't created an array. This:
string[] new_array;
should be this:
string[] new_array = new string[dr.Rows.Count - 1];
You can also throw a bit of LINQ at the problem and succinctify the code a bit:
var new_array = dr.AsEnumerable()
.Select(row => row["StuffLocationId"] as string)
.ToArray();
That's also an example of specifying the size of the array implicitly.
This way is much more clear:
dt = SuperViewBLL.GetSomeStuff();
List<string> list = new List<string>();
foreach(DataRow row in dt.Rows)
{
list.Add((!row.IsNull("StuffLocationId") ? row["StuffLocationId"] as string : string.Empty));
}
Updated with the help of #jmcilhinney
Hi I have a record called Tags in a table called Knowledgebase (KB) in my DB. The words in Tags are separated by commas. Also in the KB table is a field called Title.
I need to match the tags field to the Title so I have replaced all the commas in the tags with spaces like so string removeCommas = commas.Replace(",", " ");.
I think I now need to loop around every record in the KB table to find records? I would like to store the number of matches it finds in a variable called suggestions.
Question is what is the best way to implement the for each loop for a query like this? Is the for each loop the best method for this task?
One way is to store the space seperated strings in a List. Now, use Foreach loop for the whole table and in turn a foreach loop for each record to find the match of Title.
I will correct my answer if this is going the wrong direction, but would something like this complete the operation you are attempting?
System.Data.DataTable KB = new System.Data.DataTable();
string[] tags = "some,foo,bar".Split(',');
System.Collections.Generic.List<string> suggestions = new System.Collections.Generic.List<string>();
for (int i = 0; i < tags.Length; i++)
{
for (int j = 0; j < KB.Rows.Count; j++)
{
string row = KB.Rows[j]["Title"].ToString();
if ((row.Contains(tags[i]))
{
suggestions.Add(row);
}
}
}
Also, avoid foreach whenever humanly possible. Check out THIS post to see why.
Yes Linq can help you to retreive the data from your database and then replacing it after a foreach loop
Code Added
Let say you are using EDM and you have a context kb:
public void ReplaceCommaInTag(KbContext kb)
{
var tags = from t in kb.Titles
Select t.Tags;
foreach(Tag tag in tags)
{
tag = tag.Replace(","," ");
}
try
{
kb.SubmitChanges();
}
catch(Exception e)
{
//Display the error.
}
}
I hope it will help you
Greetings everyone-
In my code below I'm trying to add a Row from an existing DataTable (dtResult) into a new DataTable (dtCopyResult) if email address does not match. So I guess my knowledge of ADO.NET is not up to par because whenever I try to run my below code, I get an "This Row already belongs to another table". Please let me know how I can fix this..
Many Thanks
if (checkBox1.Checked)
{
for (int i = dtResult.Rows.Count - 1; i >= 0; i--) //dtResult is a DataTable
{
foreach (object email in emails) //emails is an ArrayList of email addresses
{
if (email.ToString().ToUpper() != dtResult.Rows[i][3].ToString().ToUpper())
{
dtCopyResult.Rows.Add(dtResult.Rows[i]); //dtCopyResult is a new blank DataTable that I'm trying to add rows to
}
}
}
}
As the error message tells you, a DataRow belongs to a particular DataTable; you cannot just take it and add it to another one. What you can do is either
create a new DataRow and fill it with the values from the old DataRow or
use the DataTable.ImportRow method:
dtCopyResult.ImportRow(dtResult.Rows[i]);
You can use ImportRow function, full example here http://support.microsoft.com/kb/308909
One thing I noticed is that the new row will get added multiple times; once for each item in the emails collection.
You either need to keep a local list of items already added or loop through dtCopyResult to make sure you have not already added the email.
List<string> alreadyAdded = new List<string>();
if (email.ToString().ToUpper() != dtResult.Rows[i][0].ToString().ToUpper()
&& !alreadyAdded.Contains(email.ToString()))
{
dtCopyResult.ImportRow(_dt1.Rows[i]);
alreadyAdded.Add(email.ToString());
}
it means the adding row is belong to "dtResult" and DataRow is an "Object" that represent data. Not data itselfs. so in this case u try to add DataRow object that belong to another table which will error.
another way to do is copy everything to dtCopy and delete it if condition mismatch.
Array is mainly to used to stored various type of object. In this case, if u gonna store only email u should use
List<string> emails = new List<string>();
emails.Add("test#example.com");
to enumerate rows for deleteing data
List<DataRow> removing = new List<DataRow>();
foreach(var row in table.AsEnumerable()) // or table.Rows
if(...condition)removing.Add(row);
foreach(var row in removing)table.Rows.Remove(row);
the reason to use 'removing' is if u loop through rows and removing it at the same time, means u change the enumerate which will cause error. becus .Net is not happy when u pull out something its looping.
Try replacing
dtCopyResult.Rows.Add(dtResult.Rows[i]);
with
DataRow rowToBeCopied = dtCopyResult.NewRow();
//Copy the row values..
rowToBeCopied.X = dtResult.Rows[i].X;
//Copy the remaining row values
dtCopyResult.Rows.Add(rowToBeCopied);
Best practice when converting DataColumn values to an array of strings?
[Edit]
All values for certain DataColumn for all DataTable rows to be converted to an array of string?
If I understood your goal you want to specify a particular column and return all its values as a string array.
Try these approaches out:
int columnIndex = 2; // desired column index
// for loop approach
string[] results = new string[dt.Rows.Count];
for (int index = 0; index < dt.Rows.Count; index++)
{
results[index] = dt.Rows[index][columnIndex].ToString();
}
// LINQ
var result = dt.Rows.Cast<DataRow>()
.Select(row => row[columnIndex].ToString())
.ToArray();
You could replace columnIndex with columnName instead, for example:
string columnName = "OrderId";"
EDIT: you've asked for a string array specifically but in case you're flexible about the requirements I would prefer a List<string> to avoid the need to determine the array length prior to the for loop in the first example and simply add items to it. It's also a good opportunity to use a foreach loop instead.
I would then rewrite the code as follows:
List<string> list = new List<string>();
foreach (DataRow row in dt.Rows)
{
list.Add(row[columnIndex].ToString());
}
DataRow.ItemArray Property -
http://msdn.microsoft.com/en-us/library/system.data.datarow.itemarray.aspx
Also, which version are you using? You should check out the DataTableExtensions class -
http://msdn.microsoft.com/en-us/library/system.data.datatableextensions.aspx
And the DataRowExtensions class -
http://msdn.microsoft.com/en-us/library/system.data.datarowextensions.aspx
I know this question is old, but I found it in my Google search trying to do something similar. I wanted to create a list from all the values contained in a specific row of my datatable. In my code example below, I added a SQL datasource to my project in Visual Studio using the GUI wizards and I dropped the needed table adapter into the designer.
'Create a private DataTable
Private authTable As New qmgmtDataSet.AuthoritiesDataTable
'Fill the private table using the table adapter
Me.AuthoritiesTableAdapter1.Fill(Me.authTable)
'Make the list of values
Dim authNames As List(Of String) = New List(Of String)(From value As qmgmtDataSet.AuthoritiesRow In Me.authTable.Rows Select names.authName)