Home>

preface:

Chapter 62gridview batch update data》, We customized a batch editing interface with the gridview control,Similarly, we can also customize a batch add interface.Assuming this is the case,We accept a batch of goods from Tokyo:6 different tea and coffee, if the user enters one product at a time in a detailsview control,He will repeatedly enter many of the same values,Such as the same kind (beverages), the same supplier (tokyo traders), the same discontinued value (false), and the same order value (0). Repeated input of these same values ​​is not only tiring,It's also prone to errors.Just do some extra work,We can create a batch add interface.Users only need to select supplier and category once, enter the name and unit prices of a series of products, and click a button to add these new products to the database (as shown in Figure 1). Product name and unitprice of these added products The data is specified by the two dropdownlist controls at the top of the interface.The values ​​of discontinued and unitsonorder are specified by "hard editing" and are false and 0, respectively.

Figure 1:Batch Add Interface

In this tutorial, we will create a batch add interface as shown in Figure 1.Based on the previous two chapters, we will encapsulate the addition process with transactions to ensure atomic operations.let's start!

Step 1:Create a display interface

We will create a single page with 2 areas:display area and add area.What we created in this step is the display area,It contains a gridview control for displaying products and a button button titled "process product shipment". When the button is clicked,The display interface will be replaced with an add interface as shown in Figure 1.If you click the "add products from shipment" or "cancel" button, you will return to the display page.Adding the interface will be done in the second step.

This page with 2 interfaces can only make one interface visible at a time.We will use 2 panel web controls as containers to contain these 2 interfaces-a panel web control contains an interface.

First open the batchchinsert.aspx page in the batchdata folder, and drag a panel control from the toolbox to the page in the designer mode (as shown in Figure 2), and set its id to displayinterface. The height and width properties are 50px and 125px respectively. Clear these properties in the properties window.

Figure 2:Drag a panel control from the toolbox to the page

Then drag a button and gridview control to the panel control. Set the button's id to processshipment and the text attribute to "process product shipment". Set the gridview's id to productsgrid and bind it from its smart tag to an objectdatasource named productsdatasource. Set the objectdatasource to call the getproducts method of productsbll class Since the gridview control is only used to display data,Select "(none)" from the update, insert, delete tags. Click finish to complete the setting

Figure 3:Calling the getproducts method of the productsbll class to display the data

Figure 4:Select "(none)" in the update, insert, delete tags

After setting up the objectdatasource, visual studio will automatically add some boundfields and a checkboxfield. Only the productname, categoryname, suppliername, unitprice, and discontinued columns are kept. You can make some more appearance improvements.I customized the unitprice column as a monetary value,Sorted the columns again,Some headertext values ​​have been modified.Then enabled the "pagination" and "sort" functions in the gridview's smart tab. After completing the above work,The page declaration code should look similar to the following:

<asp:panel runat="server">
 <p>
 <asp:button runat="server"
  text="process product shipment" />
 </p>
 <asp:gridview runat="server" allowpaging="true"
 allowsorting="true" autogeneratecolumns="false"
 datakeynames="productid" datasourceid="productsdatasource">
 <columns>
  <asp:boundfield datafield="productname" headertext="product"
  sortexpression="productname" />
  <asp:boundfield datafield="categoryname" headertext="category"
  readonly="true" sortexpression="categoryname" />
  <asp:boundfield datafield="suppliername" headertext="supplier"
  readonly="true" sortexpression="suppliername" />
  <asp:boundfield datafield="unitprice" dataformatstring="{0:c}"
  headertext="price" htmlencode="false"
  sortexpression="unitprice">
  <itemstyle horizontalalign="right" />
  </asp:boundfield>
  <asp:checkboxfield datafield="discontinued" headertext="discontinued"
  sortexpression="discontinued">
  <itemstyle horizontalalign="center" />
  </asp:checkboxfield>
 </columns>
 </asp:gridview>
 <asp:objectdatasource runat="server"
 oldvaluesparameterformatstring="original_ {0}"
 selectmethod="getproducts" typename="productsbll">
 </asp:objectdatasource>
</asp:panel>

We noticed that the declaration code for the button and gridview controls appeared inside thetag,Because these controls are placed in a panel control named displayinterface,We can hide these controls by setting the visible property of the panel controls to false.We will see in the third step,When a button is clicked,Programmatically change the visible property of the panel control to display the add interface.

Take a moment to log in to this page in your browser.As shown in Figure 5, you will see a button displayed as "process product shipment", and the gridview control under it lists 10 products at a time.

Figure 5:gridview lists products and enables sorting and pagination

Step 2:Create and add interface

After creating the display interface,We will create the add interface.In this tutorial,Our add interface allows users to add 5 products at the same time, and the category and supplier of these 5 products are the same,The names and nit prices are different. Below the panel control with id displayinterface,Drag a panel control from the toolbox to the page,Set its id to insertinginterface, its visible property to false, and clear its height and width property values. We will add code in the third step to change its visible property to true.

Next we will create the add interface as shown in Figure 1.The interface could have been created by some html technology,But here we will use a very simple table with 4 columns and 7 rows.

Note:Although in the designer mode you can use the toolbox's tools to add the

elements element, that will automatically add some style attribute settings that we don't need.Therefore, I prefer to add the html<table>elements element in the source view mode. After writing the class<table>declaration code,I like to switch to designer mode immediately,Add another web control and set its properties.BewareWhen you have thought about creating a few rows and columns,I tend to use static html instead of table web controls because if you use table web controls,We must access the web control placed in it by findingcontrol ("controlid"). But then again,If i want to create a dynamically-sized tables-for example, the rows and columns of the table are bound to the database or based on a user-defined standard format,I still want to use the table web control for a simple reason,We can programmatically create this table web control.

Enter the following declaration code in thetag of the panel control with id insertinginterface:

<table cellspacing="0"&​​gt;
 <tr>
 <td>supplier:</td>
 <td></td>
 <td>category:</td>
 <td></td>
 </tr>
 <tr>
 <td>product:</td>
 <td></td>
 <td>price:</td>
 <td></td>
 </tr>
 <tr>
 <td>product:</td>
 <td></td>
 <td>price:</td>
 <td></td>
 </tr>
 <tr>
 <td>product:</td>
 <td></td>
 <td>price:</td>
 <td></td>
 </tr>
 <tr>
 <td>product:</td>
 <td></td>
 <td>price:</td>
 <td></td>
 </tr>
 <tr>
 <td>product:</td>
 <td></td>
 <td>price:</td>
 <td></td>
 </tr>
 <tr>
 <td colspan="4">
 </td>
 </tr>
</table>

The "table" statement does not yet contain any web controls. We noticed that each

element has a clear css class setting:the "top row" of the dropdownlists control named supplier and category corresponds to the batchinsertheaderrow;the "add products from shipment" and "cancel" buttons The "bottom line" corresponds to batchinsertfooterrow;those containing the textbox control of product and unit price alternately use batchinsertrow and batchinsertalternatingrow. I have created the corresponding css classes in the styles.css file, the code is as follows:

/*** styles for ~/batchdata/batchinsert.aspx tutorial *** /
.batchinsertlabel
{
 font-weight:bold;
 text-align:right;
}
.batchinsertheaderrow td
{
 color:white;
 background-color:#900;
 padding:11px;
}
.batchinsertfooterrow td
{
 text-align:center;
 padding-top:5px;
}
.batchinsertrow
{
}
.batchinsertalternatingrow
{
 background-color:#fcc;
}

After entering these codes,Switch to design view,The<table>looks like a table with 4 columns and 7 rows, as shown in Figure 6:

Figure 6:Add interface as a table with 4 columns and 7 rows

Now we add web controls in the add interface. Drag two dropdownlists from the toolbox into the corresponding boxes of the table-one to display the supplier and the other to display the category.

Set the id of the dropdownlist used to display the supplier to suppliers and bind it to an objectdatasource named suppliersdatasource. Set the objectdatasource to call the getsuppliers method of the suppliersbll class. Select "(none)" in the update tag Click finish to complete the setup wizard.

Figure 7:Setting the objectdatasource to call the getsuppliers method of the suppliersbll class

Set the dropdownlist to display the companyname column, and pass the value as the supplierid column.

Figure 8:The companyname column is displayed, passing the value of the supplierid column

Set the id of the second dropdownlist to categories and bind it to an objectdatasource named categoriesdatasource. The objectdatasource calls the getcategories method of the categoriesbll class. Select "(none)" in the update tab and click finish to complete the setting . Finally set the dropdownlist control to display the categoryname column and pass the value of the categoryid column.

After adding these two dropdownlist controls and binding them to the corresponding objectdatasources, your screen should look similar to Figure 9:

Figure 9:The "header row" contains a dropdownlist control showing suppliers and categories

We now need to create a textbox control that collects name and price information for each product. Drag and drop a textbox control in the name and price boxes for each row below. Set their ids to productname1, unitprice1, productname2, unitprice2, and so on.

Add a comparevalidator control to each price textboxes, and set its controltovalidate property to the id value of the corresponding control. At the same time, set the operator property to greaterthanequal, the valuetocompare property to "0", and the type property to currency. This will ensure that the input Price is a valid currency value greater than or equal to 0.Also set the text attribute to "*";the errormessage attribute is "the price must be greater than or equal to zero. Also, please omit any currency symbols.".

Note:We do not include any requiredfieldvalidator controls in the add interface, even if the productname of the database table products is not allowed to be null. For example,If the user only wants to enter the product name and unit price in the first 3 rows, and the last 2 rows are empty, we only add 3 products to the database. Since productname is required,After entering the name value, we only need to programmatically check whether the user has entered the unit price value of the product. We will perform this check in the fourth step.

When the user enters data,But if the input value contains a currency symbol,The comparevalidator control will report invalid data.Add a "$" match in front of each unit price textboxe control to ignore the currency symbol when prompting the user to enter data.

Finally, add a validationsummary control to the inserting interface panel control, set its showmessagebox property to true and showsummary property to false. With these settings,When the user enters an invalid unit price value, an asterisk will appear next to the textbox control.And the validationsummary control will display a client message box,The corresponding error message is displayed.

At this point, your screen looks similar to Figure 10.

Figure 10:Add interface now contains a textbox control that displays the name and prices of the product

Next we need to add "add products from shipment" and "cancel" buttons to the bottom row. Drag two button controls from the toolbox to the bottom of the interface,Set their id to addproducts and cancelbutton respectively;set their text properties to "add products from shipment" and "cancel" respectively. In addition, set the causesValidation property of the cancelbutton button to false.

Finally, we need to add a label web control to display status information about these 2 interfaces.For example:When the user successfully adds a batch of products, we want to switch to the display interface and display a confirmation message.Of course, if the user only provided the price and no name information when entering product information, we need to display a warning message.Prompting the user for productname is required.Since we need to display information related to these two interfaces,Place the control above these 2 panel controls.

drag Drag a label web control from the toolbox to the top of the page,Set its id to statuslabel, clear its text property, set its visible property and enableviewstate property to false. We have discussed in previous tutorials,If the enableviewstate property is set to false, we can change the property value of the label control programmatically.When a page postback occurs, it returns to the default state.When certain user actions occur, status information is displayed,And when the page returns,The status message disappeared again.Finally, set the cssclass attribute of statuslabel to "warning". This is the css class name we defined in the styles.css file.

The following figure shows what the label control looks like after it is added and set

Figure 11:Place the label control with the status label on the panel control

Step 3:Switch between the display interface and the add interface

At this point, we have completed the display and adding interface,But we still have 2 tasks to do:

1. Switch between display interface and add interface

2. Add the product to the database

Currently, the display interface is visible and the add interface is hidden.This is because the visible property of the displayinterface panel control is true (the default), and the visible property of the inserting interface panel control is false.

When clicking the "process product shipment" button, we switched from the display interface to the add interface.To do this, create a click event handler for the button,Contains the following code:

protected void processshipment_click (object sender, eventargs e)
{
 displayinterface.visible=false;
 insertinginterface.visible=true;
}

This code just hides the displayinterface panel and shows the inserting interface panel.

Next, we create event handlers for the "add products from shipment" and "cancel" buttons in the add interface.When any button is clicked,We need to switch to the display interface.Create a click event handler for these 2 buttons to call the returntodisplayinterface method-we will create this method shortly.

apart from In addition to hiding the inserting interface panel and displaying the display interface panel, this method also needs to return the web control to its pre-editing state. That is, set the selectedindex of the dropdownlist control to 0 and clear the text property of the textbox control.

Note:Think carefully,If before returning to the display interface,What would happen if we did not return these controls to the pre-edited state?For example, the user clicks the "process products from shipment" button and enters product information.Click the "add products from shipment" button again, this will add the product and return to the display page.If the user wants to add another batch of products,Once you click the "process product shipment" button, you will switch to the add interface,However, the value of the dropdownlist control and the value of the textbox control are still the previous values.

protected void addproducts_click (object sender, eventargs e)
{
 //todo:save the products
 //revert to the display interface
 returntodisplayinterface ();
}
protected void cancelbutton_click (object sender, eventargs e)
{
 //revert to the display interface
 returntodisplayinterface ();
}
const int firstcontrolid=1;
const int lastcontrolid=5;
private void returntodisplayinterface ()
{
 //reset the control values ​​in the inserting interface
 suppliers.selectedindex=0;
 categories.selectedindex=0;
 for (int i=firstcontrolid;i<= lastcontrolid;i ++)
 {
 ((textbox) insertinginterface.findcontrol ("productname" + i.tostring ())). text =
  string.empty;
 ((textbox) insertinginterface.findcontrol ("unitprice" + i.tostring ())). text =
  string.empty;
 }
 displayinterface.visible=true;
 insertinginterface.visible=false;
}

The above two click event handlers simply call the returntodisplayinterface method, but we will complete the "add products from shipment" click event in the fourth step and add code to save the product.

The returntodisplayinterface method returns the dropdownlist control of suppliers and categories to its first item at the beginning;The constants firstcontrolid and lastcontrolid are used to set the start and end index values ​​of the textboxe control that indicates the product name and unit price in the add interface, respectively. Set the text property of these controls to an empty string in a for loop.Finally, reset the visible property of the panels control to display the display interface and hide the add interface.

Take a moment to test the page in your browser,When you log in for the first time, you will see the screen shown in Figure 5,Click the "process product shipment" button, the page will be transferred back to the add interface as shown in Figure 12,No matter if you click the "add products from shipment" or "cancel" button, you will return to the display interface.

Note:When browsing the add interface,Test the validation controls corresponding to the unit price textbox.If you do not enter a currency value or the price is less than 0, when you click the "add products from shipment" button, a client-side warning message will pop up.

Figure 12:After clicking the "process product shipment" button, it will switch to the add interface.

Step 4:Add Products

The remaining thing to do is to add products to the database in the click event handler of the "add products from shipment" button.To do this, we can create a productsdatatable and add a productsrow instance for the product to be inserted. Once productsrows have been added, we call and pass the productsdatatable to the updatewithtransaction method of the productsbll class. Remember that we were in Chapter 61, "Encapsulating database modifications in transactionsThe updatewithtransaction method created in "" passes the productsdatatable to the updatewithtransaction method of productstableadapter. Then an ado.net transaction is started, and tableadatper issues an insert command to the database for each productrow added. If all additions are correct, the transaction is committedOtherwise, the transaction is rolled back.

coding When encoding the click handler for the "add products from shipment" button,Should perform some error checking,Because we did not use the requiredfieldvalidators control in the add interface, a user may enter the price of the product and ignore its name. Since the name of the product is required,If this happens,We need to alert the user and interrupt the inserts operation. The complete code is as follows:

protected void addproducts_click (object sender, eventargs e)
{
 //make sure that the unitprice comparevalidators report valid data ...
 if (! page.isvalid)
 return;
 //add new productsrows to a productsdatatable ...
 northwind.productsdatatable products=new northwind.productsdatatable ();
 for (int i=firstcontrolid;i<= lastcontrolid;i ++)
 {
 //read in the values ​​for the product name and unit price
 string productname=((textbox) insertinginterface.findcontrol
  ("productname" + i.tostring ())). text.trim ();
 string unitprice=((textbox) insertinginterface.findcontrol
  ("unitprice" + i.tostring ())). text.trim ();
 //ensure that if unitprice has a value, so does productname
 if (unitprice.length>0&&productname.length == 0)
 {
  //display a warning and exit this event handler
  statuslabel.text="if you provide a unit price you must also" +
  "include the name of the product.";
  statuslabel.visible=true;
  return;
 }
 //only add the product if a product name value is provided
 if (productname.length>0)
 {
  //add a new productsrow to the productsdatatable
  northwind.productsrow newproduct=products.newproductsrow ();
  //assign the values ​​from the web page
  newproduct.productname=productname;
  newproduct.supplierid=convert.toint32 (suppliers.selectedvalue);
  newproduct.categoryid=convert.toint32 (categories.selectedvalue);
  if (unitprice.length>0)
  newproduct.unitprice=convert.todecimal (unitprice);
  //add any "default" values
  newproduct.discontinued=false;
  newproduct.unitsonorder=0;
  products.addproductsrow (newproduct);
 }
 }
 //if we reach here, see if there were any products added
 if (products.count>0)
 {
 //add the new products to the database using a transaction
 productsbll productsapi=new productsbll ();
 productsapi.updatewithtransaction (products);
 //rebind the data to the grid so that the producst just added are displayed
 productsgrid.databind ();
 //display a confirmation (don "t use the warning css class, though)
 statuslabel.cssclass=string.empty;
 statuslabel.text=string.format (
  "{0} products from supplier {1} have been added and filed under" +
  "category {2}.", products.count, suppliers.selecteditem.text,  categories.selecteditem.text);
 statuslabel.visible=true;
 //revert to the display interface
 returntodisplayinterface ();
 }
 else
 {
 //no products supplied!
 statuslabel.text="no products were added. please enter the product" +
  "names and unit prices in the textboxes.";
 statuslabel.visible=true;
 }
}

Start The event handler initially checks whether the value returned by the page.isvalid property is true. If it returns false, it means that at least one comparevalidators control found invalid data.At this point, we either stop adding products;When the unit price value entered by the user is assigned to the unitprice property of productsrow,It ends with throwing an exception.

Next, create a new productsdatatable instance instance (that is, products), in a for loop, iterate over the textbox control about name and unit price, and read its text attribute into the local variables productname and unitprice. If the user enters a product Unit price value without entering the name of the product, the statuslabel control will display the message "if you provide a unit price you must also include the name of the product" and exit the event handler.

If the user enters a product name, use the newproductsrow method of productsdatatable to create a new productsrow instance instance. For the productname attribute of the instance,Is assigned with the corresponding textbox;for the supplierid and categoryid attributes,The value is selected by adding the selectedvalue property of the corresponding dropdownlist control at the top of the interface;If the user enters the price of the product,Assign a value to the unitprice property of the productsrow instance.If the user did not enter a price then leave it blank,When adding data to the database, the value of unitprice is null. Finally, the hard-coded values ​​"false" and "0" are assigned to the discontinued and unitsonorder properties, respectively.

After completing the assignment of the relevant attributes of the productsrow instance instance,Add it to productsdatatable.

After completing the for loop we will check if the product has been added.After all, the user may click the "add products from shipment" button without entering any information. If at least one product exists in the productsdatatable,The updatewithtransaction method of the productsbll class will be called, and the gridview control named productsgrid is rebind.The newly added product will appear in the display interface.statuslabel will be updated to display a confirmation message,Then call returntodisplayinterface to hide the add interface and display the display interface.

If no products are added,The add interface will still be hidden,However, a message "no products were added. Please enter the product names and unit prices in the textboxes" will be displayed.

Figure 13 shows the situation where the user entered the unit price value without entering the corresponding product name;Figure 14 shows the display interface after successfully adding 3 products.Figure 15 shows the interface of two of these products (and one on the previous page)

Figure 13:When entering the unit price value, the product name is also required

Figure 14:Added three veggies products from supplier mayumi

Figure 15:The newly added product can be found on the last page in gridview

Note:The batch addition logic used in this article encapsulates the insert in a transaction.To confirm,We can intentionally import a database-level error. For example, for the categoryid attribute of the productsrow instance instance,We do not use the selected value of the categories dropdownlist control to assign a value as above.Instead, assign it a value using i * 5.Here i refers to the loop indexer between 1 and 5. Therefore, when adding 2 or more products,The categoryid value (5) of the first product is valid,The categoryid value of the following products is invalid,Because its value does not match the categoryid value in the categories category (translation:because the categoryid value of the second product is 10;the third is 15, and so on). The consequence is that the insert operation of the first product is successful,Subsequent operations failed,Because the foreign key constraint was violated.Since our batch of additions is atomic,The first insert will be rolled back and the database will return to the state before the batch addition started

Conclusion:

In this article and the first two chapters, we created an interface for batch update, batch delete, and batch add data.These interfaces all use transactions.The matter, we are in Chapter 61Encapsulating database modifications in transactions》 Added in the data access layer.In some cases,These batch data processing interfaces can greatly improve the efficiency of end users.

To The review of processing batch data ends here.In the next series we will look at a number of more advanced cases in the data access layer.This includes using stored procedures in tableadapter's methods, setting connection- and command-level settings in dal, and encrypting connection strings.

Happy programming!

About the Author

  • Previous Sixty-ninth of Manipulating Data in ASPNET 20: Handling Computed Columns
  • Next Working with Data in ASPNET 20 Part 68: Adding Additional Columns to the DataTable