I have created an application that shows data in data table. it also provide user interface for adding new column to a data table with its default value.
But problem is, It showing newly created column in data table but default value is not coming. I have to populate data table again to do this which reduces my app performance.
So, how do i overcome this problem...
EDIT:
obj_dataTable.Columns.Add(columnName);
int index = obj_dataTable.Columns.IndexOf(obj_dataTable.Columns[columnName]);
obj_dataTable.Columns[index].DefaultValue = defaultValue;
Default values are assigned when you add a row to the table and the column is not already assigned a value. Therefore, existing rows will not be updated when you change the schema. If you want a generic means of updating a table and applying the default to existing rows then Id create a method to copy the rows from the current data table to a new data table with the extra column in it. Eg:
void doTableStuff()
{
DataTable table1 = makeTable();
table1.Rows.Add(new string[] { "Frederic", "Robert" });
table1 = updateTable(table1);
if (table1.Rows[0]["Sam"] == "Samantha")
{
Console.WriteLine("I Was Right!");
}
else
{
Console.WriteLine("I Was Wrong!");
}
}
DataTable makeTable()
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn { ColumnName = "Fred", DataType = typeof(string), DefaultValue = "fred" });
dt.Columns.Add(new DataColumn { ColumnName = "Bob", DataType = typeof(string), DefaultValue = "bob" });
return dt;
}
DataTable updateTable(DataTable oldTable)
{
DataTable newTable = makeTable();
newTable.Columns.Add(new DataColumn { ColumnName = "Sam", DataType = typeof(string), DefaultValue = "Samantha" });
newTable.Merge(oldTable, true, MissingSchemaAction.Add);
return newTable;
}
Sorry, I didn't try running this but you should get the idea. Hope that works.
Cheers
Related
I have a DataTable that is populated with only strings at the moment.
I want to get from the DataTable Columns the DataType and insert the DataType.
DataTable example, all row names can be random.
And I want to have from the example Column "age" as int, and the rest still string.
At the moment the Age is a string, can I try to Parse the whole column? Or would this be a bad solution.
Is there a simple way to do this?
You can not change the data type once the table is loaded. Clone the current DataTable from the original table, find the age column, change data type from string to int then import rows.
Important: The above assumes that, in this case the age column can represent an int on each row, if not you need to perform proper assertion before using ImportRow.
Here is a conceptual example
private static void ChangeColumnType()
{
DataTable table = new DataTable();
table.Columns.Add("Seq", typeof(string));
table.Columns.Add("age", typeof(string));
table.Columns.Add("name", typeof(string));
table.Rows.Add("1", "22", "Smith");
table.Rows.Add("2", "46", "Jones");
DataTable cloned = table.Clone();
bool found = false;
for (int index = 0; index < table.Columns.Count; index++)
{
if (string.Equals(table.Columns[index].ColumnName, "age",
StringComparison.CurrentCultureIgnoreCase))
{
cloned.Columns["age"]!.DataType = typeof(int);
found = true;
}
}
if (!found) return;
foreach (DataRow row in table.Rows)
{
cloned.ImportRow(row);
}
foreach (DataColumn column in cloned.Columns)
{
Console.WriteLine($"{column.ColumnName}\t{column.DataType}");
}
}
Edit: One possible way to avoid issues when age can not be converted to an int.
if (!found) return;
foreach (DataRow row in table.Rows)
{
if (int.TryParse(row.Field<string>("age"), out _))
{
cloned.ImportRow(row);
}
else
{
Console.WriteLine($"Failed: {string.Join(",", row.ItemArray)}");
}
}
Sorry if I do not understand your question but I will try to answer what I think you're asking below:
If you're just trying to determine the data type then I would suggest taking the first value in said column (as you don't need to check them all obviously.) And do a tryparse to determine if it is compatible with int for example.
If you used getType it would likely return a String.
If you're trying to SET the whole column as a data type then you should probably be doing this at the stage you're generating the table via a constructor or programatically as shown in the first example
// Create second column.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "ParentItem";
column.AutoIncrement = false;
column.Caption = "ParentItem";
column.ReadOnly = false;
column.Unique = false;
// Add the column to the table.
table.Columns.Add(column);
Full Example from Microsoft
I have a Datatable. For example :
private DataTable GetGenericDatatable(){
DataTable retval = new DataTable();
retval.Columns.Add("ProtocolNumber");
retval.Columns.Add("Name");
retval.Columns.Add("Company");
retval.Columns.Add("Department");
retval.Columns.Add("VisitDate");
retval.Columns.Add("DispatchTargetName");
retval.Columns.Add("DayOffCount");
// add data ...
return retval;
}
I want to insert some columns between "Department" and "VisitDate" columns dynamically even the datatable is full with data.
We can do this by creating new datatable, creating the columns again etc. but it is a dirty solution. Any idea for a clear solution?
You can assign a DefaultValue to the DataColumm:
DataTable tbl = GetGenericDatatable();
tbl.Columns.Add(new DataColumn("Col1") { DefaultValue="def. value"});
tbl.Columns.Add(new DataColumn("Col2", typeof(DateTime)) { DefaultValue = DateTime.Now });
This value will be applied to every existing row in the table.
You can use SetOrdinal to set the index of a column. For example:
tbl.Columns["Col1"].SetOrdinal(tbl.Columns.IndexOf("VisitDate"));
tbl.Columns["Col2"].SetOrdinal(tbl.Columns.IndexOf("VisitDate"));
Now the new columns are between Department and VisitDate, Col1 before Col2.
Add a new DataColumn and use the SetOrdinal method to set its position:
var col = retval.Columns.Add("New Column");
col.SetOrdinal(4);
You could use this Extension:
namespace System
{
public static class Extensions
{
public static void AddColumnAfter(this DataColumnCollection columnCollection, string afterWhichColumn, DataColumn column)
{
var columnIndex = columnCollection.IndexOf(afterWhichColumn);
columnCollection.Add(column);
columnCollection[column.ColumnName].SetOrdinal(columnIndex + 1);
}
}
}
Example:
DataTable table = new DataTable();
table.Columns.Add("Column 1");
table.Columns.Add("Column 2");
table.Columns.Add("Column 3");
table.Columns.AddColumnAfter("Column 1", new DataColumn("Column 4"));
I am trying to bind DataTable to DataGridView as below;
DataTable table = new DataTable();
foreach (ConsumerProduct c in ctx.ConsumerProducts)
{
DataRow row = table.NewRow();
row["Id"] = c.ID;
row["Model"] = c.Model;
row["Status"] = "Offline";
table.Rows.Add(row);
}
dataGridView1.DataSource = table;
I get exception at the first line itself row["Id"]
Column 'Id' does not belong to table .
P.S. I have already added these columns in the designer view of dataGridView.
You just created a blank DataTable and then you are trying to add data to particular columns like Id, Model and Status.
You have to add those columns as well.
DataTable table = new DataTable();
table.Columns.Add("Id");
table.Columns.Add("Model");
table.Columns.Add("Status", typeof(string)); //with type
There is no issue in biding.
Also you can project your required column to an Anonymous type and then bind that to your data grid like:
var result = ctx.ConsumerProducts
.Select(r=> new
{
Id = r.ID,
Model = r.Model,
Status = "Offline"
}).ToList();
dataGridView1.DataSource = result;
Hi. I have a DataTable one of the column is set to AutoIncrement is true. Basically I am adding some text box values to the DataTable and then binding it to the Grid View. What I am trying to achieve is if I delete a row from the grid view the row in the DataTable is also need to be deleted and also decrement the primary key column.
DataTable is declared like this private DataTable table = new DataTable(); and code is:
DataColumn promoDetailsID = new DataColumn();
promoDetailsID.ColumnName = "promoDetailsID";
promoDetailsID.DataType = System.Type.GetType("System.Int32");
promoDetailsID.AutoIncrement = true;
promoDetailsID.AutoIncrementSeed = 1;
promoDetailsID.AutoIncrementStep = 1;
table.Columns.Add(promoDetailsID);
table.Columns.Add("StartRange", typeof(string));
table.Columns.Add("EndRange", typeof(string));
table.Columns.Add("Amount", typeof(string));
table.Columns.Add("AllocationCases", typeof(string));
table.Columns.Add("AllocationUnits", typeof(string));
if (ViewState["dtTable"] != null)
{
table = (DataTable)ViewState["dtTable"];
}
table.Rows.Add(null,TxtStartRange.Text.Trim(), TxtEndRange.Text.Trim(), TxtAllocationAmount.Text.Trim(), TxtAllocationCases.Text.Trim(), TxtAllocationUnits.Text.Trim());
grdPromotions.DataSource = table;
grdPromotions.DataBind();
ViewState["dtTable"] = table;
This is the code when I am trying to delete row from grid.
protected void grdPromotions_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
if (ViewState["dtTable"] != null)
{
table = (DataTable)ViewState["dtTable"];
int rowIndex = Convert.ToInt32(e.RowIndex);
table.Rows[e.RowIndex].Delete();
}
table.AcceptChanges();
grdPromotions.DataSource = table;
grdPromotions.DataBind();
ViewState["dtTable"] = table;
}
There is no error I am getting but the DataTable is not updating after delete.
Since you don't use a real database it makes no sense to use DataRow.Delete which just sets it's RowState to Deleted. What you want to do is to remove the row from the DataTable.
table.Rows.RemoveAt(e.RowIndex);
If you also want to decrement the primary key column, you have to make the column writable:
table.Columns[0].ReadOnly = false;
Then you need to update the value manually:
int counter = 0;
foreach(DataRow row in table.Rows)
{
row[0] = ++counter;
}
table.Columns[0].ReadOnly = true;
Side-note: don't store a DataTable in ViewState, if you need to persist it between postbacks use the Session instead. Session lives in memory whereas ViewState will be serialized and stored in the rendered html, so it will also be transferred to the client.
I am trying to explain what I need to do.
As you can see in the second foreach, I am iterating over the temporary data table, but I need to set a value for the same row in the original data tablerow.
For example:
_uc090_WingsIntegrationDataSet.WingsBookingInterface[0]["property"] = x;
What I dont know how to implement is how to find that row and set the property, I saw the LoadRow method but I never used it before.
DataTable tempTable = _uc090_WingsIntegrationDataSet.WingsBookingInterface.Clone();
DataRow[] datarows = _uc090_WingsIntegrationDataSet.WingsBookingInterface.Select("REFMDossierID = " + refmDossierId);
if (datarows.Length > 0)
{
foreach (DataRow dr in datarows)
{
tempTable.ImportRow(dr);
}
}
//2. foreach master row
foreach (UC090_WingsIntegrationDataSet.WingsBookingInterfaceRow row in tempTable.Rows)
You can find the row using Rows.Find(), but it requires that a PrimaryKey be set on at least one column in your DataTable.
As far as loading new data, you can use LoadDataRow() which will update existing rows (if a primary key is supplied) or insert new data if any matching datatypes are found.
Please take a look at the following example using untyped datasets:
DataSet dataSet = new DataSet("MyDataSet");
DataTable dataTable = dataSet.Tables.Add("JavaScriptLibraries");
DataColumn[] dataColumns =
new[] {
new DataColumn("Id", typeof(Int32))
{
AutoIncrement = true,
AllowDBNull = false,
AutoIncrementSeed = 1
},
new DataColumn("Name", typeof(String))
};
dataTable.Columns.AddRange(dataColumns);
dataTable.PrimaryKey = new[] { dataTable.Columns["Id"] };
DataRow dataRow1 = dataTable.NewRow();
dataRow1["Name"] = "jQuery";
dataTable.Rows.Add(dataRow1);
DataRow dataRow2 = dataTable.NewRow();
dataRow2["Name"] = "MooTools";
dataTable.Rows.Add(dataRow2);
// Copy the dataset
DataSet tempDataSet = dataSet.Clone();
DataTable tempDataTable = tempDataSet.Tables["JavaScriptLibraries"];
DataRow[] tempRows = dataSet.Tables["JavaScriptLibraries"].Select("Name = 'jQuery'");
// Import rows to copy of table
foreach (var tempRow in tempRows)
{
tempDataTable.ImportRow(tempRow);
}
foreach (DataRow tempRow in tempDataTable.Rows)
{
// Find existing row by PK, then update it
DataRow originalRow = dataTable.Rows.Find(tempRow["Id"]);
originalRow["Name"] = "Updated Name";
}
// Load new data using LoadDataRow()
object[] newRow = new[] { null, "New Row" };
dataTable.BeginLoadData();
dataTable.LoadDataRow(newRow, true);
dataTable.EndLoadData();