I have DataTable in my application. It holds DataColumns and Rows. I just want to call it recursively and input to InnerXml query. here Field names should be DataColumns values and Value should be Row value of DataTable. Bellow is my tried code. But I don't have idea to iterate DataTable and fill InnerXml.
DataTable DT = new DataTable();
for(int i=0 ; i<DT.Length ;i++){
batchElement.InnerXml =
"<Method ID='4' Cmd='New'>" + "<Field Name='" + DT.DataColumn[] + "'>" + DT.row + "</Field></Method>";
}
Please help me.
Do you want to simply enumerate a DataTable or do you actually want to recursively iterate it? I only ask because you example code does not show recursion, it shows enumeration with a couple parts that won't compile.
I'm guessing that you are attempting to serialise the datatable, in which case the following example would probably work:
StringBuilder innerXml = new StringBuilder();
int methodId = 0;
foreach(DataRow row in DT.Rows)
{
innerXml.AppendFormat("<Method ID='{0}' Cmd='New'>", methodId.ToString());
methodId += 1;
foreach(DataColumn column in DT.Columns)
{
innerXml.AppendFormat("<Field Name='{0}'>{1}</Field>", column.ColumnName, row[column.ColumnName]);
}
innerXml.AppendLine("</Method>");
}
batchElement.InnerXml = innerXml.ToString();
Apologies if the above does not compile - handtyped - should hopefully put you on the right track though.
NB: I'm not really sure, based on your example, how you intend to split the row and cell elements in Xml. I've made some assumptions on the Xml structure but hopefully it's enough for you to work from
Related
Update: even though I have got the required result but when the the second function access the data table the value is still the same
It a sequential program with two functions in different classes. First sort and second replace function. So it should sort the value and other function should be able to retrieve the sorted table but when it retrieve the datatable it gives the unsorted table.
I have used acceptchanges() but it also give the same result.
The program is trying to sort the table according to the required field and the result is stored in Sorted table variable. I am trying to copy this to the original i-e sourceTables but it is not working and is adding another row instead of updating [As shown in below dig]. I have tried to copy whole table but it does not work and by adding rows it is not giving the required result. I have used different methods but I am not getting the required result.
List<DataTable> sourceTables = context.GetDataByTable(sourceTable.StringValue);
List<DataTable> targetTables = context.GetDataByTable(targetTable.StringValue, sourceTables.Count);
string orderDesc= orderField.StringValue + " DESC";
for (int i = 0; i < sourceTables.Count; i++)
{
DataView dv = sourceTables[i].DefaultView;
if (orderDirection.StringValue == OrderDirectionAsc)
{
// for Sorting in Ascending Order
dv.Sort = orderField.StringValue;
}
else
{
// for Sorting in Descending Order
dv.Sort = orderDesc;
}
DataTable sortedTable = dv.ToTable();
DataTable dttableNew = sortedTable.Clone();
//sourceTables[i] = sortedTable.Copy();
//targetTables[i] = dv.ToTable();
//targetTables[i] = sortedTable.Copy();
// foreach (DataRow dr in sortedTable.Rows)
//// targetTables[i].Rows.Add(dr.ItemArray);
//}
for (int j = 0; j < sourceTables[i].Rows.Count; j++)
{
if (sourceTable.GetValue().ToString() == targetTable.GetValue().ToString())
{
foreach (DataRow dr in sortedTable.Rows)
{
targetTables[i].Rows.Add(dr.ItemArray);
}
else
{
foreach (DataRow dr in sortedTable.Rows)
{
targetTables[i].Rows.Add(dr.ItemArray);
}
// targetTables[i] = sortedTable.Copy(); does not work
//foreach (DataRow drtableOld in sortedTable.Rows)
//{
// targetTables[i].ImportRow(drtableOld);
//}
Instead of replacing the first values it is adding more rows
any help would be appreciated
If any one have problem with duplicate data or the changes are only local and is not effecting the original data table. Remember to always use .ImportRow(dr) function to add rows to the table and if you use Tables[i].Rows.Add(dr.ItemArray); the changes will affect only the local table and not the original one. Use .clear to remove the old rows from the orginal table. The action done directly on the original function will only effect the rows. If it is done on the clone copy changes will nor affect the original table.
Here is the complete code
DataTable sortTable = dv.ToTable();
if (sTable.GetValue().ToString() == tTable.GetValue().ToString())
{
sTables[i].Clear();
foreach (DataRow dr in sortTable.Rows)
{
sTables[i].ImportRow(dr);
}
sTables[i].AcceptChanges();
}
DataTable distinctTable = dTable.DefaultView.ToTable(true,"ITEM_NO","ITEM_STOCK");
DataTable dtSummerized = new DataTable("SummerizedResult");
dtSummerized.Columns.Add("ITEM_NO",typeof(string));
dtSummerized.Columns.Add("ITEM_STOCK",typeof(double));
int count=0;
foreach(DataRow dRow in distinctTable.Rows)
{
count++;
//string itemNo = Convert.ToString(dRow[0]);
double TotalItem = Convert.ToDouble(dRow[1]);
string TotalStock = dTable.Compute("sum(" + TotalItem + ")", "ITEM_NO=" + dRow["ITEM_NO"].ToString()).ToString();
dtSummerized.Rows.Add(count,dRow["ITEM_NO"],TotalStock);
}
Error Message: Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier.
Do anyone can help me out?
Thanks.
You might try this:
dTable.Compute("sum([" + TotalItem + "])","");
I.e enclose your column name in square brackets [ ]
The idea is from this post.
The problem is exactly about your DataType of the column. If you have a row with dynamically added columns without DataType like that (it may be a result of a manual calculation or cross-tab query-like)
myTable.Columns.Add("AddedColumn");
You will probably face with the column conversion issue.
Instead, If you change your add method with pointing DataType like below
myTable.Columns.Add("AddedColumn", typeof(System.Int32));
It will work I think. It's what I experienced & fixed before...
You want to write:
dTable.Compute("sum(CONVERT(ITEM_STOCK, 'System.Double'))",
"ITEM_NO='" + dRow["ITEM_NO"].ToString() + "'")
instead of:
dTable.Compute("sum(" + TotalItem + ")", "ITEM_NO="...
because it will translate to dTable.Compute("sum(value_of_TotalItem), "ITEM_NO="..., value_of_TotalItem is a double and is not a column name.
See DataTable.Compute
UPDATE:
try this:
DataTable distinctTable = dTable.Clone();
dTable.Columns.Add("ITEM_STOCK_D", typeof(Decimal),
"CONVERT(ITEM_STOCK, 'System.Decimal')");
foreach (DataRow dRow in dTable.Rows)
{
String itemNo = dRow["ITEM_NO"].ToString();
if(distinctTable.Select(String.Format("ITEM_NO = '{0}'",itemNo)).Length == 0)
{
double totalStock = Convert.ToDouble(dTable.Compute("SUM(ITEM_STOCK_D)",
String.Format("ITEM_NO = '{0}'", itemNo)));
distinctTable.Rows.Add(itemNo, totalStock.ToString());
}
}
dTable.Columns.Remove("ITEM_STOCK_D");
In my case the issue was with my query itself.
My query returned difference of two columns. Like, query="Select A,B,A-B from Table" and I was performing sum on datatable using compute function as dt.Compute("Sum(A-B)","").
So, datatable was unable to compute the sum of A-B column. I gave the difference column alias as query="Select A,B,(A-B) as AB from Table"
and dt.Compute("Sum(AB)","").
Thus, resolved the error.
I'm trying to get the column names using the code below but it returns a weird stuff... It returns a lot of "properties" (including the column name), all I want is a list of the columns names in the resultset. Am I doing something wrong ?
reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
DataTable schema = reader.GetSchemaTable();
DataRow myField = schema.Rows[0];
//For each property of the field...
foreach (DataColumn myProperty in schema.Columns)
{
host.WriteLine("##--> " + myProperty.ColumnName + " = " + myField[myProperty].ToString());
}
Thanks in advance people :)
Miloud B.
reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
DataTable schema = reader.GetSchemaTable();
//For each property of the field...
foreach (DataRow row in schema.Rows)
{
host.WriteLine("##--> " + row["ColumnName"]);
}
Note: I am writing this code without IDE. Please be kind.
I have a dataset. I added a column "Tags". I need to run a function to update the value, for each row one at a time, for the "Tags" column. Here's what I've tried so far, tell me what I'm missing.
public System.Data.DataSet PopulateDataGrid(int nViewMode)
{
System.Data.DataSet ds = _data.GetGridView(nViewMode)
ds.Tables[0].Columns.Add("Tags", typeof(string));
foreach (System.Data.DataRow dr in ds.Tables[0].Rows)
{
dr.BeginEdit();
dr.ItemArray.SetValue(_dataFactory.GetPartTags(_dataFactory.ExecuteScalar("SELECT POSITION FROM PARTS WHERE PART_ID = " + dr.ItemArray.GetValue(0)).ToString()), dr.ItemArray.Length - 2);
dr.SetModified();
dr.EndEdit();
dr.AcceptChanges();
}
ds.AcceptChanges();
return ds;
}
Yeah, I know I could put using System.Data and wouldn't have to put it in my code, but this is the only function out of many using that, so I didn't want to do that (if there's no damage to loading time, then I may). I wish I just needed to run a query and that's it, but this needs to be filled in code. If someone could help, that'd be great. Thanks.
Edit: And I've also verified that _dataFactory.GetPartTags(_dataFactory.ExecuteScalar("SELECT POSITION FROM PARTS WHERE PART_ID = " + dr.ItemArray.GetValue(0)).ToString()) returns the value I want. It just shows up blank in the DataGridView. The column is there, but nothing is populated.
You should be able to just use:
dr["Tags"] = _dataFactory.GetPartTags(_dataFactory.ExecuteScalar("SELECT POSITION FROM PARTS WHERE PART_ID = " + dr.ItemArray.GetValue(0)).ToString())
You should take note that the SetModified() method marks the row as modified, and AcceptChanges() clears the Modified/New/Deleted flags. Unless you have underlying code to store that data somewhere or do something more with it automatically, it's a little redundant. Same thing with the ds.AcceptChanges(). And if you try to use an adapter later on modified/new rows to push them to the database after you've done an AcceptChanges() on the rows/dataset, they won't be found as modified/new/deleted, and the changes won't be pushed to the database.
I am trying to make a messagebox text provide datatable results. Below is a snippet of code that I have written so far:
String mystring = comboBox1.Text;
if (mystring.Substring(0, 12) == ("Company Name"))
{
textBox2.Text = mystring.Substring(13);
ADOCon.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\Name\Desktop\SmallBizDb.mdb";
ADOCon.Open();
OleDbCommandBuilder CBuilder = new OleDbCommandBuilder(DAdapter);
DAdapter = new OleDbDataAdapter("Select Companies.Company_Name From Companies Where Companies.Company_Name = '" + textBox2.Text + "'", ADOCon);
DAdapter.Fill(DTable);
MessageBox.Show(DTable.ToString());
ADOCon.Close();
ADOCon.Dispose();
}
else
Basically, if an end user types "Company Name-Company One", for example, I would like a message box to appear stating the datatable (DTable) information, which comes from a sql query. Currently, I have "messagebox.Show(DTable.ToString());", which does not work. Also, all other examples I have seen use Row indexes, such as ".Rows[0]", which I cannot use since row numbers are not involved, but rather column names and record names from the sql "where" statement within the data adapter.
There is a lot fluff here, so my major issue is how to convert my datable results so that they will show up in a message box.
Thank you,
DFM
I'm not certain what you are wanting, but if you want to display the values in your datatable you should be able to get the data from it and display it in any order you want. I think you are wanting to do something like
System.Text.StringBuilder b = new System.Text.StringBuilder();
foreach (System.Data.DataRow r in dt.Rows)
{
foreach (System.Data.DataColumn c in dt.Columns)
{
b.Append(c.ColumnName.ToString() + ":" + r[c.ColumnName].ToString());
}
}
MessageBox.Show(b.ToString());
This will loop through all the rows returned, and for each row (each company in the results) add the details in the form ColumnName:ActualValue of the dataTable.
Of course I'm not certain displaying an unknown amount of data in a message box like this is a good idea, that's just a way you can do it.