Check for key duplicates in Gridview Frontend ASP.NET C# - c#

A person can have many bills.
Each bill can have many (Item, Quantity) entries.
My primary key is (Bill_No,Item_Code) .
For each Bill_no, I can enter a particular Item_Code only once.
I enter the (Item,Quantity) details via a Grid View as shown.
Can I validate this at the front end on Create Indent click so that an Item_no entered once in the gridView cannot be entered again before submit is clicked?
I have done the back end primary key validation in the Data Access Layer. It just ignores the duplicate Item_No and continues with an alert.
I want to check for duplicate Item_code entries row-wise via front end so no data is lost on create.

//to check repeated item in the gridview
int rowIndex = 0;
if (ViewState["CurrentTable"] != null)
{
DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
if (dtCurrentTable.Rows.Count > 1)
{
for (int i = 1; i <= dtCurrentTable.Rows.Count-1; i++)
{
if (dtCurrentTable.Rows.Count > 1)
{
TextBox prevItem = (TextBox)Grid_ItemList.Rows[rowIndex].Cells[1].FindControl("itemCode");
if (prevItem.Text == itemcode && currentRow.RowIndex != rowIndex)
{
ClientScript.RegisterStartupScript(Page.GetType(), "validation1", "<script language='javascript'>alert('Item Alredy Added, Please change the Qty if needed.')</script>");
txt.Text = "";
qtyl.Enabled = false;
return;
}
}
rowIndex++;
}
}
SetRowData();
}
put this code inside your dropdownlist onselected index change function, just before you populate the itemcode.

Even if you'd check it against the data in your grid it would be possible that paging is enabled. Then the grid only stores the data of the current page.
Apart from that, even without paging you'll have the problem that another user could add a record at the same time with the same Bill_no+Item_Code.
So there is no other/better way than to handle the constraint exception of the database. Therefore you need to add an unique index on the combination of Bill_no+Item_Code.
Assuming SQL-Server as rdbms, you can use the SqlException's Number property:
string error = "";
try
{
CreateIndent();
} catch (SqlException ex)
{
switch (ex.Number)
{
case 2627: // Unique Index/ Primary key Violation/ Constraint Violation
case 2601: // Unique Index/Constraint Violation
error = "Bill_no and Item_Code are not unique";
break;
default:
error = "Unknown SQL-Exception";
break;
}
}
// show error
Update
Suppose I enter (Apple,10) , (Apple,20) and (Apple,40) as three items
of my gridview, my only option is to have (Apple,10) enter the
database and the other entries error out?
string
unique=((TextBox)Grid_ItemList.Rows[rowIndex].Cells1.FindControl("itemCode")).‌​ToString();
This is how I get my data in each row. Now how do I check for
uniqueness?
If you insist on checking the GridView row by row which won't work with paging or if another user uses this page simultaneously, this should work:
var allItems = Grid_ItemList.Rows.Cast<GridViewRow>()
.GroupBy(r => new {
ItemValue = ((DropDownList)r.FindControl("DdlItemName")).SelectedValue,
ItemCode = ((TextBox) r.FindControl("itemCode")).Text.Trim()
});
var duplicates = allItems.Where(g => g.Count() > 1);
// show somewhere on the page, for example on an error-panel or label
LblError.Text = "Duplicates detected: " +
string.Join(",", duplicates.Select(d => d.ToString()));
Of course you could also use a loop to check if all combinations are unqiue.

Related

does OnAutoGeneratingColumn e.cancel affect Table.Column.Count?

If I use OnAutoGeneratingColumn to cancel some columns that I don't necessarily want to generate, will it affect the number of columns in Table.Columns.Count?
Context
I'm iterating through a table, row by row, taking each value and passing it through to an insert SQL command. Right now it lines up so that each entry is associated properly. Will I disrupt this with e.cancel? Will row[1] no longer point to what it once did if row[0] was e.cancel'd?
for (int i = 0; i < table.Dummy.Columns.Count; i++)
{
// if we're past our first entry, add room for the next before entering it
if (i != 0)
{
InsertIntoTableQuery.AddIntPrm();
}
//if our column has an entry, add it into our table.
if (row[i] != null)
{
InsertIntoTableQuery.Prms[i].Val = row[i];
}
}
No! I figured out why I was erroring and this wasn't the cause. you can cancel column generation in the wpf datagrid without actually altering the table index's. In hindsight that's pretty obvious.

Stored Proceedure or GridView DataSource

I've built a frontend to update an individual column for selected records in a GridView. I've gotten that all setup the way that I want it to work including performing a check to be sure that more than one row is selected (via a template field checkbox I added to the GridView) and that a column has been selected from a dropdown list.
I have everything down to the block of code that has to be built to do the actual update of the column for the selected rows. This will cycle through each row, so if I've selected 5 rows it would trigger this code 5 times and update the record ID associated with that row.
I'm mainly debating with myself which would be the simplest to build into this. I at first thought about doing a stored procedure on the SQL Server and feeding it the record ID, column to update, and the value to write in the update. But then I got to thinking about it and realized that I have a GridView with a Data Source that was already setup to update the record as long as I called it
In either case I'll need to refresh the GridView after the update has been completed.
Just wondering what others might think would be the cleanest approach to this and just what my options might be. I've never seen a multi row column edit implemented so figure someone may have a better idea than me on how to go about this.
Here is my code block for the update as it is right now...
protected void SaveColEditBtn_Click(object sender, EventArgs e)
{
//Read the column select drop down List into Local Varriables
String SelectedColumnItem = ColumnSelectDDL.SelectedItem.ToString();
String SelectedColumnValue = ColumnSelectDDL.SelectedValue.ToString();
List<int> EditRows = new List<int>();
List<string> recordnumber = new List<string>();
foreach (GridViewRow grv in ActVulListGV.Rows)
{
if (((CheckBox) grv.FindControl("TagRowChkBx")).Checked == true)
{
//get current row rowindex if checkbox in it is checked
EditRows.Add(grv.RowIndex);
//get the record number (RecID)
recordnumber.Add(grv.Cells[2].Text.ToString());
}
}
int[] ERows = EditRows.ToArray();
if (recordnumber.Count > 1)
{
if (ColumnSelectDDL.SelectedValue.ToString() == "TicketNumber")
{
// Save Ticket number //
}
else if (ColumnSelectDDL.SelectedValue.ToString() == "TicketClosed")
{
// Save Ticket Closed Value //
}
else if (ColumnSelectDDL.SelectedValue.ToString() == "Notes")
{
// Save Notes //
}
else if(ColumnSelectDDL.SelectedValue.ToString() == "Exception_ID")
{
// Save Exception ID //
}
EditColMsgLbl.Font.Bold = true;
SelectedRowsMsgLbl.Font.Bold = true;
ColEditPnlExt.Show();
EditColLbl.Text = SelectedColumnItem;
SelectedRowsLbl.Text = "";
foreach (string record in recordnumber)
{
// Insert the call of the procedure here to update the database
}
}
else
{
UserMessageLbl.Text = " *** Choose 2 or more rows to use column edit feature! ***";
mpePopUp.Show();
}
}
It depends. If you are updating all at once, by looping, use a Stored Procedure. However updating one by one with EditIndex, it is easier to use the source. However I would recommend using code behind and a SP to update a row, then you could use the same SP for updating a single or all rows.
See this excellent tutorial. It covers all the basics of GridView editing and updating.
And a tip if you have some time to spare in the near future, try to disable ViewState for the GridView. It will save a lot of tranfer kb's and overhead. But get the above to work first ;)

how to optimize a "foreach" event from a gridview in asp.net webform?

I have an Event that starts when a TextBox text is changed in c#.net.
The Event goes over a GridView rows. The GridView is created with information from a DB. This GridView has eight TemplateFields, seven with TextBox and one with a DropDownList control.
The problem is that this Event is taking between 26 and 27 seconds.
Foreach row, it should:
Check if the [4] column content is equal to "BATCH" and, if true, paint the
entire row with a different color.
Extract the ID from the [0] column.
Use this ID and the Date from a TextBox for a Query that will look
if the record already exists in the DB.
If the record exists, it should print it into the TextBox and DropDownList from the TemplateField.
If some of the records in the database are empty, there's a few
TextBox that shouldn't print it.
Additional Information:
The GridView is created with data from the DB, using a QUERY
inside a SqlDataSource. This happens in the same event. This
QUERY contains some INNER JOIN, the data is not stored in the
same DB Table:
SELECT Dealer.IDDealer, Batch.IDBatch, Lpars.Nombre, Dealer.DealerCodigo, Batch.Nombre AS Expr1, Batch.CTStart AS Expr2 FROM Lpars INNER JOIN Dealer ON Lpars.IDLpar = Dealer.IDLpar INNER JOIN Batch ON Dealer.IDDealer = Batch.IDDealer INNER JOIN [1Monday] ON Batch.IDBatch = [1Monday].IDBatch WHERE (Batch.Status = 'Enabled') ORDER BY Batch.CTStart
The response time issue is not because the SQL QUERY at the top. I tried it
separatelly and the SQL Server response time for this query is less
than 2 seconds.
There is some DATETIME data that I extract from the DB. So, before
I print it into the TextBox, I need to change the DATETIME format
to my needs. That's why I store the extracted data into variables
before print it.
Here is my code:
-
//WHEN THE TEXT FROM TEXTBOX CHANGES:
protected void TextDate_TextChanged(object sender, EventArgs e)
{
//THE GRIDVIEW IS CREATED:
GridView1.DataSourceID = DatosLunes.ID;
GridView1.DataBind();
//A) I CREATE VARIABLES TO CHARGE THE DATA THAT CAMES FROM THE DATABASE WHEN PROCEED WITH THE QUERY
string VarsDateGV;
string VarsStartGV;
string VarsScchkGV;
string VarsEndGV;
string VarsDurationGV;
string VarsBeforeGV;
string VarsAfterGV;
//B) FOREACH ROW, THE PROCESS START TO:
foreach (GridViewRow row in GridView1.Rows)
{
//B.1) IDENTIFY EACH CONTROL INTO ROW COLUMNS:
TextBox DateGV = row.FindControl("DateGV") as TextBox;
TextBox StartGV = row.FindControl("StartGV") as TextBox;
TextBox ScchkGV = row.FindControl("ScchkGV") as TextBox;
TextBox EndGV = row.FindControl("EndGV") as TextBox;
TextBox DurationGV = row.FindControl("DurationGV") as TextBox;
HiddenField DedicatedGV = row.FindControl("DedicatedGV") as HiddenField;
HiddenField NotDedicatedGV = row.FindControl("NotDedicatedGV") as HiddenField;
DropDownList DropDownGV = row.FindControl("DropDownGV") as DropDownList;
TextBox BeforeGV = row.FindControl("BeforeGV") as TextBox;
TextBox AfterGV = row.FindControl("AfterGV") as TextBox;
DateTime FechaCT1 = DateTime.Parse(TextDate.Text, CultureInfo.InvariantCulture);
//B.2) IF THE [4] COLUMN STRING IS EQUAL TO "BATCH", THE ROW IS PAINTED
if (row.RowType == DataControlRowType.DataRow)
{
string NombreBatch = row.Cells[4].Text;
if (NombreBatch == "BATCH")
{
row.BackColor = System.Drawing.Color.NavajoWhite;
}
}
//B.3) THE QUERY STARTS
if (row.RowType == DataControlRowType.DataRow)
{
// B.3.1) EXTRACTS THE ROW ID FROM [0] COLUMN
string IDBatch = row.Cells[0].Text;
//B.3.2) USE A DATATABLE TO CHARGE DATA FROM THE QUERY "TRAEFILAHO"
CADCATOPS.DSCATOPS.BatchDatos1DataTable Fila = CADCATOPS.CADBatchHandoff.TraeFilaHO(Convert.ToInt32(IDBatch), Convert.ToString(FechaCT1));
//B.3.3) FOREACH ROW IN THE DATATABLE, THE DB INFORMATION IS SAVED INTO THE VARIABLES CREATED BEFORE (IN THE "A" ITEM).
foreach (DataRow row1 in Fila.Rows)
{
VarsDateGV = row1["FechaBatch"].ToString();
VarsStartGV = row1["Inicio"].ToString();
VarsScchkGV = row1["FinDedicado"].ToString();
VarsEndGV = row1["FinNoDedicado"].ToString();
VarsDurationGV = row1["DuracionBatch"].ToString();
DropDownGV.Text = row1["Estado"].ToString();
VarsBeforeGV = row1["DuracionBefore"].ToString();
VarsAfterGV = row1["DuracionAfter"].ToString();
/********* FROM NOW ON:
B.3.3.1) I VALIDATE IF THE DATETIME DATA EXTRACTED FROM THE DB EXISTS FOR A FEW ITEMS. IF EXISTS, THE FORMAT IS CHANGED FOR MY NEEDS, AND PRINTED.
MAYBE YOU ARE ASKING WHY I VALIDATE IT FOR SEPARATED AND NOT ALL TOGETHER, THIS IS BECAUSE I NEED TO CHECK IT SEPARATELLY.
IF "THIS" DATA DOESN'T EXISTS, DON'T BRING IT TO THE GRIDVIEW, BUT IF "THIS OTHER" DATA EXISTS, I NEED TO SHOW IT.
*********/
if (VarsDateGV != "")
{
DateTime VardDateGV = DateTime.Parse(VarsDateGV, CultureInfo.InvariantCulture);
DateTime VardStartGV = DateTime.Parse(VarsStartGV);
DateGV.Text = VardDateGV.ToString("MM/dd/yyyy");
StartGV.Text = VardStartGV.ToString("HH:mm");
}
if (VarsEndGV != "")
{
DateTime VardEndGV = DateTime.Parse(VarsEndGV);
DateTime VardDurationGV = DateTime.Parse(VarsDurationGV);
EndGV.Text = VardEndGV.ToString("HH:mm");
DurationGV.Text = VardDurationGV.ToString("HH:mm");
}
if (VarsScchkGV != "")
{
DateTime VardScchkGV = DateTime.Parse(VarsScchkGV);
ScchkGV.Text = VardScchkGV.ToString("HH:mm");
}
if (VarsBeforeGV != "")
{
DateTime VardBeforeGV = DateTime.Parse(VarsBeforeGV);
BeforeGV.Text = VardBeforeGV.ToString("HH:mm");
}
if (VarsAfterGV != "")
{
DateTime VardAfterGV = DateTime.Parse(VarsAfterGV);
AfterGV.Text = VardAfterGV.ToString("HH:mm");
}
}
}
} //FOREACH LOOP IS COMPLETED.
}
Do you have any reccomendation to optimize this event?
UPDATE: ConnorsFan helps me to detect the issue (Thank you).
The issue is the query, because it runs 50 times (or the GridView lenght). I tried avoiding it and the response was less than 4 seconds. The problem is that I need it to work with the query. Is there a way to optimize the code for it?
Then the total number of iterations is around 100 iterations. That shouldn't take very long at all.
Can you use the Stopwatch class on the beginning and end of the event handler and get a total miliseconds count for the execution of the function - at present there doesn't seem to be any reason to expect the code to be slow. We need to separate the execution speed of the code to the time taken to refresh the UI.
Alternatively follow the advice here How to suspend a DataGridView while updating its columns to suspend the GridView painting and reformatting during the execution of your changes, then resume the layout after you have finished.
I assume that TextDate is outside of the GridView. As I understand it, your inner query returns a single record. You could modify it to return all the records that you will need inside the loop (including the IDBatch field), and run it before entering the loop. Inside the loop, you would find the specific record with the primary key (as indicated here).
protected void TextDate_TextChanged(object sender, EventArgs e)
{
...
CADCATOPS.DSCATOPS.BatchDatos1DataTable AllFila = CADCATOPS.CADBatchHandoff.AllTraeFilaHO(Convert.ToString(FechaCT1));
AllFila.PrimaryKey = new DataColumn[] { AllFila.Columns["IDBatch"] };
foreach (GridViewRow row in GridView1.Rows)
{
....
if (row.RowType == DataControlRowType.DataRow)
{
string IDBatch = row.Cells[0].Text;
DataRow foundRow = AllFila.Rows.Find(IDBatch);
...
}
}
}
You could make it faster if the records in the DataTable returned by the query are sorted the same way as in the GridView. The row indexes would match, and you wouldn't need to find the row in the DataTable.
UPDATE
If the TextBox data can be obtained directly from the data source that populates the GridView, you can eliminate the foreach loop (and all the related processing). You can use the second parameter of Eval to format the data:
<asp:TextBox ID="DateGV" runat="server" Text='<%# Eval("FechaBatch", "{0:MM/dd/yyyy}") %>' ... />
<asp:TextBox ID="StartGV" runat="server" Text='<%# Eval("Inicio", "{0:HH:mm}") %>' ... />

Cannot insert duplicate key row in object 'dbo.ta_Kullanici' with unique index 'IX_ta_Kullanici'.\r\nThe statement has been terminated

I try to develop a program for insert datas from excel table to SqlServer.
I had an error when I try to insert data to sqlserver. That is my error message here
"Cannot insert duplicate key row in object 'dbo.ta_Kullanici' with
unique index 'IX_ta_Kullanici'.\r\nThe statement has been terminated."
ID is unque and autoincrement In my table.
Thanks for your help! :)
A part of my code is here;
if (!check)
{
kul = new ta_Kullanici();
hata = new KullaniciHata();
hata.AdSoyad = kullanicilar.Rows[i][7].ToString() + " " + kullanicilar.Rows[i][8].ToString();
hatalar.Add(hata);
kul.kul_ad = kullanicilar.Rows[i][7].ToString();
kul.kul_soyad = kullanicilar.Rows[i][8].ToString();
foreach (var bolge in bolgeler)
{
if (kullanicilar.Rows[i][1].ToString().ToLower().IndexOf(bolge.bolge_ad.ToLower()) != -1)
{
kul.kul_bolge_Id = bolge.bolge_Id;
}
}
kul.kul_ikTar = DateTime.Now;
kul.kul_statu = true;
kul.kul_guid = Guid.NewGuid().ToString();
kul.kul_ikIP = "127.0.0.1";
kul.kul_ik_kul_Id = 5;
kul.kul_TCKNo = kullanicilar.Rows[i][9].ToString();
kul.kul_kulAd = kullanicilar.Rows[i][6].ToString();
kul.kul_tip_enm = 2;
if (!string.IsNullOrWhiteSpace(kullanicilar.Rows[i][9].ToString()))
{
kul.kul_sifre = kullanicilar.Rows[i][9].ToString();
}
else
{
kul.kul_sifre = "123123";
}
checkList.Add(kul);
db.ta_Kullanici.Add(kul);
db.SaveChanges();
hatalar.Remove(hata);
}
Have a look at the table in question dbo.ta_Kullanici and see what column the index named IX_ta_Kullanici is on.
The index in question is a unique index, meaning that it will not allow any duplicate values for the column(s)
Remember that this index could be on any column in the table and is not limited to the Primary Key.
So basically the issue is that the column has an index of Unique key and what that index does is that it makes sure duplicate values do not get repeated on the column, to change that what you can do is to go to Management studio, go to the table that has that column, right-click on the column and click to modify. A screen will appear with all the columns displayed. right-click the small box beside the column and select indexes/keys. Then you will see a IsUnique property. set it to 'NO'.

Error with Insert in Datagridview

I have a usersdataTable with an "Code" column I set as PK and auto-increment "true" in MySql DB.
I want users to fill in values for first name, last name, username etc on a datagrid view but cannot enter the Code value.
I have this code for update/insert:
private void usersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
try
{
if (dgvUsers.RowCount > 0)
{
for (int i = 1; i <= dgvUsers.RowCount; i++)
{
var code = dgvUsers.Rows[i].Cells[0].Value.ToString();
if (code == string.Empty)
{
// add users
this.usersTableAdapter.Insert(
dgvUsers.Rows[i].Cells[1].Value.ToString(),
dgvUsers.Rows[i].Cells[2].Value.ToString(),
dgvUsers.Rows[i].Cells[3].Value.ToString(),
GlobalClass.MD5Hash(dgvUsers.Rows[i].Cells[4].Value.ToString()),
DateTime.Now,
null
);
}
else
{
// edit users
this.usersTableAdapter.Update(this.eko_payrollDataSet.users);
}
}
}
MessageBox.Show("Details Updated Successfully");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Table Structure:
Code int NN PK Autoincrement
firstName Varchar NN
lastName Varchar NN
userName Varchar NN
password varchar NN
created datetime NN
modified datetime Null?
I dragged the datagridview to the form from a dataset that created a binding source. When I press the + button to add a new row and when finished entering the values, I get a NoNullAllowedExeption for column Code when I move the cursor to another row or attempt to add a row below this.
What do I need to do to fix this? I have not added validation code that would cause this.
I have seen the same problem I am experiencing here http://www.databaseforum.info/5/857494.aspx
When your PK is an auto-increment column, the associated column in the DataSet should have its proper AutoIncrement and AutoIncrementSeed, if not you should be able to set them in the dataset designer.
Here is an issue similar to yours, look if you can find something useful.
autoincrement-values-in-autogenerated
I think there is little about your problem, can you put an example or put all the properties of the dataset/datatable and gridview.
Good luck.

Categories

Resources