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.
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
Here is my code:
private void AddAutoIncrementColumn(DataTable dt)
{
DataColumn column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.AutoIncrement = true;
column.AutoIncrementSeed = 0;
column.AutoIncrementStep = 1;
dt.Columns.Add(column);
}
I have an existing DataTable and want to create an auto-incremented column. That is, when i create the column i want it to automatically fill in the value 0......x. I am using the code above. But it doesn't seem to work. Any suggestions?
Try This
private void AddAutoIncrementColumn()
{
DataColumn column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.AutoIncrement = true;
column.AutoIncrementSeed = 0;
column.AutoIncrementStep = 1;
// Add the column to a new DataTable.
DataTable table = new DataTable("table");
table.Columns.Add(column);
}
There is a method on Datatable called CreateDataReader. So, clone your original datatable, add the identity column, create a datareader from the original table, then load the cloned table with the data reader. This will generate numbers in the identity column in the cloned table, then discard the original table and use the clone, eg
// original data table
DataTable origDT;
// create a reader
DataReader dr = origDT.CreatDataReader();
//clone original
DataTable clonedDT = origDT.Clone();
//add identity column
clonedDT.Columns.Add(new DataColumn(){AutoIncrement=true});
//load clone from reader, identity col will auto-populate with values
clonedDT.Load(dr);
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;
My homework is in ASP.NET and my prof wants me to delete a row from a gridview that doesn't use a SqlDataSource. Is this possible? Because I think my prof wants to fail me just because I asked a question and he wasn't able to answer it.
Yes you can delete a row from gridview that doesn't use sqldatasource. All you have to do is delete the row from the source (whatever the source is...), that is bind to your gridview.
heres sample code for the issue:
public static DataTable dt;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dt = new DataTable();
DataRow dr = null;
dt.Columns.Add(new DataColumn("RowNumber", typeof(string)));
dt.Columns.Add(new DataColumn("Column1", typeof(string)));
dt.Columns.Add(new DataColumn("Column2", typeof(string)));
dr = dt.NewRow();
dr["RowNumber"] = 1;
dr["Column1"] = "column1cell";
dr["Column2"] = "column2cell";
dt.Rows.Add(dr);
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
protected void LinkButton1_Click(object sender, EventArgs e)
{
if (dt.Rows.Count > 0)
{
dt.Rows.RemoveAt(0);
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
not the best code, but if your prof wants you to do, here you are.
hope this helps you...
I you Just want to delete the row find the row index and the simply call the method
datagridview.rows.removeat(rowindex);
There is a better way without having to rebind the Gridview and it forcing a call to the SqlDataSource.
Use ViewState.
When you load the Gridview, save the "data" into a ViewState variable.
ie:
//ok let's load the gridview with data as normal and display it
//'sdsClasses' is the SQL data source
gvStudents.DataSourceID = "sdsClasses";
gvStudents.DataSource = null; // Null out the source, as we have a SourceID instead
gvStudents.DataBind(); //load the gridview and display it
//save the data in a viewstate for later use
DataView dvClasses = (DataView)sdsClasses.Select(DataSourceSelectArguments.Empty);
DataTable dt = new DataTable();
if (dv != null)
{
dt = dvClasses.ToTable();
ViewState["gv"] = dt;
}
So now when ever the Gridview loads, you have the data its used in memory as a ViewState.
If you need to delete a row, do this ...
In my example I am using a search feature to look for the row I want to delete, based on a SelectValue from a dropdownlist control. You'll have to use something like that to pin-point the row you want to delete. If you wanted to delete the last row, then do a ForEach on the DataTable, row-by-row until you get to the last row and delete!
//Load the dataview that was already saved in the ViewState
DataTable dt = (DataTable)ViewState["gv"];
//find the student in the datatable, row by row
bool found = false;
bool wsAtt = false; //flag to indicate if the student is already in the roll or not saved yet (ie: sdsClasses recordset)
foreach (DataRow dr in dt.Rows)
{
//compare studentID in the datatable with the selected value of the student to delete
//check that the field has TECNQ studentIDs otherwise use the 2nd cell in the row
if (dr[0].ToString().Contains("NQ"))
found = (found || dr[0].ToString() == ddlRemoveStudents.SelectedValue);
else
{
found = (found || dr[1].ToString() == ddlRemoveStudents.SelectedValue);
wsAtt = true;
}
//he should!
if (found)
{
//remove the row to the datatable
dt.Rows.Remove(dr);
//Bind the grid view to the datatable and refresh
gvStudents.DataSource = dt;
gvStudents.DataSourceID = null; // Null out the id, we have a source
gvStudents.DataBind();
//update the viewstate with the new amount of rows
ViewState["gv"] = dt;
}
}
So you can see, using a ViewState as a replacement to the SqlDataSource, you're able to manipulate the Gridview as you wish and never call the original SqlDataSource again, except the first time to get the data.
And tell your professor he's an arrogant pig.
How to add identity column to datatable using c#. Im using Sql compact server.
You could try something like this maybe?
private void AddAutoIncrementColumn()
{
DataColumn column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.AutoIncrement = true;
column.AutoIncrementSeed = 1000;
column.AutoIncrementStep = 10;
// Add the column to a new DataTable.
DataTable table = new DataTable("table");
table.Columns.Add(column);
}
DataTable table = new DataTable("table");
DataColumn dc= table.Columns.Add("id", typeof(int));
dc.AutoIncrement=true;
dc.AutoIncrementSeed = 1;
dc.AutoIncrementStep = 1;
// Add the new column name in DataTable
table.Columns.Add("name",typeof(string));
table.Rows.Add(null, "A");
table.Rows.Add(null, "B");
table.Rows.Add(null, "C");
If the DataTable is already populated. you can use below method
void AddAndPopulateDataTableRowID(DataTable dt, string col, bool isGUID)
{
if(isGUID)
dt.Columns.Add(col, typeof(System.Guid));
else
dt.Columns.Add(col, typeof(System.Int32));
int rowid = 1;
foreach (DataRow dr in dt.Rows)
{
if (isGUID)
dr[col] = Guid.NewGuid();
else
dr[col] = rowid++;
}
}
You don't do autoincrement on DataTable (or front-end for that matter), unless you want to make your application a single user application only.
If you need the autoincrement, just do it in database, then retrieve the autoincremented id produced from database to your front-end.
See my answer here, just change the SqliteDataAdapter to SqlDataAdapter, SqliteConnection to SqlConnection, etc : anyway see why I get this "Concurrency Violation" in these few lines of code??? Concurrency violation: the UpdateCommand affected 0 of the expected 1 records
Just my two cents. Auto-increment is useful in a Winform app (stand alone as Michael Buen rightly said), i.e.:
DatagridView is being used to display data that does not have a "key field", the same can be used for enumeration.
I dont think its a good idea to use autoincrement on datatable if you are using insert and delete to a datatable because the number will not be rearranget, no final i will share a small idea how can we use autoincrement manual.
DataTable dt = new DataTable();
dt.Columns.Add("ID",typeof(int));
dt.Columns.Add("Produto Nome", typeof(string));
dt.Rows.Add(null, "A");
dt.Rows.Add(null, "B");
dt.Rows.Add(null, "C");
for(int i=0;i < dt.Rows.Count;i++)
{
dt.Rows[i]["ID"] = i + 1;
}
always when finalizing the insert or delete must run this loop
for(int i=0;i < dt.Rows.Count;i++)
{
dt.Rows[i]["ID"] = i + 1;
}