Asp.net2.0 the creation of a business logic layer for data manipulation

Source: Internet
Author: User
Tags bind bool constructor count empty implement insert visual studio
Asp.net| Create | data

  Introduction

The data access layer, described in the first section of this tutorial, is a clear distinction between presentation logic and data access logic, as in the case of Layer, the following referred to as DAL. However, even if the DAL separates the details of data access from the presentation layer, it cannot handle any business rules. For example, we may not want the "category number" or "vendor number" of products in the product table that are marked "deactivated" to be updated; We may also need to apply some seniority rules, such as we don't want to be managed by someone who is less than our own qualifications. Another common scenario is authorization, for example, that only users with special privileges can delete a product or change the unit price.

We can actually think of the business Logic layer (Business Logic Layer, BLL) as a bridge between the data access layer and the presentation layer, and in this section we'll discuss how to integrate these business rules into a BLL. It should be explained that in a real-world application, BLL is implemented in the form of class libraries, but in order to simplify the structure of the project, in this tutorial we will implement BLL as a series of classes in the App_Code folder. The graph has always shown the structural relationship between the presentation layer, the BLL, and the DAL.


Figure one: BLL separates the presentation layer from the Dal and joins the business rules


First step: Create BLL Class

Our BLL consists of 4 classes, each of which corresponds to a TableAdapter in the DAL, which are read, inserted, modified, and deleted from their TableAdapter to apply the appropriate business rules.

To make a clearer distinction between dal and BLL classes, we created two subfolders in the App_Code folder, named Dal and BLL respectively. You just need to right-click the App_Code folder in Solution Explorer (Solution Explorer) and select New folder to create a new subfolder. After the two folders have been built, move the typed dataset (Typed DataSet) created in the first section to the Dal folder.

Then, create 4 class files in the BLL folder. Again, you just need to right-click the BLL folder in the Solution Explorer (Solution Explorer) and select New Item, and then select Class template in the pop-up dialog box to create a new class file. Each of these four files is named Productsbll, CATEGORIESBLL, SUPPLIERSBLL, and EMPLOYEESBLL.


Figure Two: Add 4 new classes to the BLL folder


Next, let's add some methods to these newly created classes and simply wrap those methods in the TableAdapter in the first section. Now, these methods will only use the methods in the DAL directly, and we'll add some business logic to them later.

Note: If you are using Visual Studio Standard version or above (that is, you are not using the visual Web Developer), you can also use Class Designer to visualize your class design. You can get more information about this new feature of Visual Studio on the Class Designer blog.

In the PRODUCTSBLL class, we need to add 7 methods altogether:

· GetProducts () – Return all products

· Getproductbyproductid (ProductID) – returns the product of the specified ProductID

· Getproductsbycategoryid (CategoryID) – returns the product of the specified category

· Getproductsbysupplier (SupplierID) – returns the product of the specified vendor

· Addproduct (ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued) – Adds a product information to the database and returns the ProductID for the newly added product

· UpdateProduct (ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, discontinued, ProductID) – updates a product that already exists in a database, returns true if one record is updated, or returns false

· Deleteproduct (ProductID) – Delete products that specify ProductID

ProductsBLL.cs

1using System;
2using System.Data;
3using System.Configuration;
4using system.web;
5using System.Web.Security;
6using System.Web.UI;
7using System.Web.UI.WebControls;
8using System.Web.UI.WebControls.WebParts;
9using System.Web.UI.HtmlControls;
10using northwindtableadapters;
11
12[system.componentmodel.dataobject]
13public class PRODUCTSBLL
14{
Private ProductsTableAdapter _productsadapter = null;
Protected ProductsTableAdapter Adapter
17 {
get {
if (_productsadapter = null)
_productsadapter = new ProductsTableAdapter ();
21st
return _productsadapter;
23}
24}
25
26
27[system.componentmodel.dataobjectmethodattribute (System.ComponentModel.DataObjectMethodType.Select, True)]
Public northwind.productsdatatable getproducts ()
29 {
return adapter.getproducts ();
31}
32
[System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Select, false)]
northwind.productsdatatable getproductbyproductid (int productID)
35 {
Return Adapter.getproductbyproductid (ProductID);
37}
38
39[system.componentmodel.dataobjectmethodattribute (System.ComponentModel.DataObjectMethodType.Select, false)]
Public northwind.productsdatatable Getproductsbycategoryid (int CategoryID)
41 {
Adapter.getproductsbycategoryid (CategoryID);
43}
44
45[system.componentmodel.dataobjectmethodattribute (System.ComponentModel.DataObjectMethodType.Select, false)]
Northwind.productsdatatable public Getproductsbysupplierid (int supplierID)
47 {
Adapter.getproductsbysupplierid (SupplierID);
49}
[System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Insert, True)]
Wuyi public bool Addproduct (string productName, int? supplierID, int? CategoryID, String QuantityPerUnit,
Decimal? UnitPrice, short? UnitsInStock, short? UnitsOnOrder, short? ReorderLevel,
BOOL discontinued)
54 {
55//Create a new Productrow instance
Northwind.productsdatatable products = new northwind.productsdatatable ();
Northwind.productsrow Product = products. Newproductsrow ();
58
Product. ProductName = ProductName;
if (SupplierID = null) product. Setsupplieridnull (); else product. SupplierID = Supplierid.value;
The IF (CategoryID = null) product. Setcategoryidnull (); else product. CategoryID = Categoryid.value;
The IF (QuantityPerUnit = null) product. Setquantityperunitnull (); else product. QuantityPerUnit = QuantityPerUnit;
The IF (UnitPrice = null) product. Setunitpricenull (); else product. UnitPrice = Unitprice.value;
The IF (UnitsInStock = null) product. Setunitsinstocknull (); else product. UnitsInStock = Unitsinstock.value;
(UnitsOnOrder = null) product. Setunitsonordernull (); else product. UnitsOnOrder = Unitsonorder.value;
The IF (ReorderLevel = null) product. Setreorderlevelnull (); else product. ReorderLevel = Reorderlevel.value;
Product. Discontinued = discontinued;
68
69//Add new product
Products. Addproductsrow (product);
int rowsaffected = adapter.update (products);
72
73//If just one new record is added, return true, or false
The return rowsaffected = = 1;
75}
76
[System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, True)]
public bool UpdateProduct (string productName, int? supplierID, int? CategoryID, String QuantityPerUnit,
The decimal? UnitPrice, short? UnitsInStock, short? UnitsOnOrder, short? ReorderLevel,
discontinued bool, int ProductID)
81 {
Northwind.productsdatatable products = Adapter.getproductbyproductid (ProductID);
The IF (products. Count = 0)
84//No matching records found, return false
return false;
86
Northwind.productsrow product = Products[0];
88
Product. ProductName = ProductName;
The IF (SupplierID = null) product. Setsupplieridnull (); else product. SupplierID = Supplierid.value;
The (CategoryID = = null) product. Setcategoryidnull (); else product. CategoryID = Categoryid.value;
(QuantityPerUnit = null) product. Setquantityperunitnull (); else product. QuantityPerUnit = QuantityPerUnit;
(UnitPrice = null) product. Setunitpricenull (); else product. UnitPrice = Unitprice.value;
if (UnitsInStock = null) product. Setunitsinstocknull (); else product. UnitsInStock = Unitsinstock.value;
The IF (UnitsOnOrder = null) product. Setunitsonordernull (); else product. UnitsOnOrder = Unitsonorder.value;
(ReorderLevel = null) product. Setreorderlevelnull (); else product. ReorderLevel = Reorderlevel.value;
The product. Discontinued = discontinued;
98
99//More new product record
int rowsaffected = adapter.update (product);
101
102///If just one record is updated, returns True, otherwise returns false
The return rowsaffected = = 1;
104}
105
[System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Delete, True)]
The public bool Deleteproduct (int ProductID)
108 {
109 int rowsaffected = Adapter.delete (ProductID);
110
111///If a record is just deleted, return true, or false
112 return rowsaffected = = 1;
113}
114}
115
Methods such as GetProducts, Getproductbyproductid, Getproductsbycategoryid, and Getproductbysuppliersid simply call the methods in the DAL directly to return the data. In some cases, however, we may also need to implement some business rules (such as authorization rules, different users, or no roles should be able to see different data), and now we can simply make them. So, for these methods, BLL is simply acting as a proxy between the presentation layer and the DAL.

Both the Addproduct and UpdateProduct methods use the product information in the parameters to add or update a product record. Because there are many fields in the product table that allow null values (CategoryID, SupplierID, UnitPrice ...). And so on), so the corresponding parameters in Addproduct and updateproduct use nullable types. Nullable types is a new technology provided in. NET 2.0 that indicates whether a value type can be empty. In C #, you can add a question mark (for example, int x;) After a value type that is allowed to be empty. For more information about nullable types, you can refer to C # programming Guide.

Since inserts, modifications, and deletions may not affect any rows, all three methods return a BOOL value to indicate whether the operation was successful. For example, page developers use a nonexistent ProductID to invoke Deleteproduct, and it is clear that the DELETE statement submitted to the database will have no effect, so deleteproduct will return false.

Note: When we add or update the details of a product, we accept a scalar list of product information instead of directly accepting a Productsrow instance. Because Productsrow is inherited from Ado.net DataRow, and DataRow does not have a default parameterless constructor, in order to create an instance of Productsrow, we must first create an instance of productsdatatable and then call its newproductr Ow method (as we did in the Addproduct method). However, when I use ObjectDataSource to insert or update, the disadvantage of doing so will be exposed. Simply put, the ObjectDataSource try to create an instance of the input parameter, and if the BLL method wants a productsrow, then ObjectDataSource will attempt to create one, but it is clear that such an operation will fail, Because there is no default parameterless constructor. Detailed information on this issue can be found in the following two posts in the ASP.net forum: updating objectdatasources with strongly-typed datasets, Problem with ObjectDataSource and Strongly-typed DataSet.

Then, in Addproduct and UpdateProduct, we created a Productsrow instance and assigned the incoming argument to it. When assigning values to a DataRow datacolumns, validation of various field levels can be triggered. Therefore, we should manually verify the incoming parameters to ensure that the data passed to the BLL method is valid. Unfortunately, the strongly typed dataset (strongly-typed DataRow) generated by Visual Studio does not use nullable values. To show that a DataColumn in DataRow can accept null values, we must use the Setcolumnnamenull method.

In UpdateProduct, we first use the Getproductbyproductid (ProductID) method to read the product information that needs to be updated. There seems to be no need to do this, but we will demonstrate that this extra action is useful in the subsequent course on concurrency optimization (optimistic concurrency). Concurrent optimization is a technology that guarantees two users to manipulate one data at a time without conflict. Getting the entire record can also make it easier to create a method that updates only a subset of the DataRow, and we can find such an example in the Suppliersbll class.

Finally, notice that we add a DataObject tag to the PRODUCTSBLL class (that is, [System.ComponentModel.DataObject] above the class declaration statement), There are also dataobjectmethodattribute tags on each method. The DataObject label marks this class as being able to bind to a ObjectDataSource control, while Dataobjectmethodattribute illustrates the purpose of the method. We'll see in later tutorials that the ObjectDataSource of ASP.net 2.0 makes it easier to access data from a class. For the ObjectDataSource Wizard to filter the existing classes appropriately, only the classes marked as DataObject are displayed by default in the class list. Of course, the PRODUCTSBLL class can work without this tag, but plus it makes it easier and more enjoyable to operate in the ObjectDataSource Wizard.

   add another class

After completing the PRODUCTSBLL class, we also add some classes for categories, suppliers, and employees services. Let's take a moment to create the following class, based on the example above:

· CategoriesBLL.cs

o GetCategories ()

o Getcategorybycategoryid (CategoryID)

· SuppliersBLL.cs

o Getsuppliers ()

o Getsupplierbysupplierid (SupplierID)

o Getsuppliersbycountry (country)

o Updatesupplieraddress (SupplierID, Address, city, country)

· EmployeesBLL.cs

o GetEmployees ()

o Getemployeebyemployeeid (EmployeeID)

o Getemployeesbymanager (ManagerID)

The Updatesupplieraddress method in the Suppliersbll class is a noteworthy thing. This method provides an interface for updating only vendor address information. It first reads a supplierdatarow (using the Getsupplierbysupplierid method) based on the specified SupplierID, sets all its properties on the address, and then calls the Supplierdatatable Update method. The code for the Updatesupplieraddress method looks like this:

Updatesupplieraddress

1[system.componentmodel.dataobjectmethodattribute (System.ComponentModel.DataObjectMethodType.Update, True)]
2public bool Updatesupplieraddress (int SupplierID, string address, String city, String country)
3{
4 northwind.suppliersdatatable suppliers = Adapter.getsupplierbysupplierid (SupplierID);
5 if (suppliers. Count = 0)
6//No matching items found, return false
7 return false;
8 Else
9 {
Northwind.suppliersrow supplier = Suppliers[0];
11
The IF (address = = null) supplier. Setaddressnull (); else supplier. address = address;
if (city = = null) supplier. Setcitynull (); else supplier. City = city;
if (country = = null) supplier. Setcountrynull (); else supplier. Country = Country;
15
16//Update the supplier's information about the address
int rowsaffected = adapter.update (supplier);
18
19///If just one record is updated, returns True, otherwise returns false
rowsaffected = = 1;
21}
22}
23
You can download the complete code for the BLL class from the link at the top of the page.

Step Two: Access the typed DataSet through the BLL class

In the first section of this tutorial, we give an example of using a typed dataset directly, but after we add the BLL class, the presentation layer can work through BLL. In the allproducts.aspx example in the first section of this tutorial, ProductsTableAdapter is used to bind the product list to the GridView, and the code looks like this:

1 ProductsTableAdapter productsadapter = new ProductsTableAdapter ();
2 Gridview1.datasource = Productsadapter.getproducts ();
3 Gridview1.databind ();
To use the new BLL class, all we need to do is simply modify the first line of code. Replace ProductsTableAdapter with PRODUCTBLL objects:

1 PRODUCTSBLL productlogic = new PRODUCTSBLL ();
2 Gridview1.datasource = Productlogic.getproducts ();
3 Gridview1.databind ();
The BLL class can also be explicitly accessed by using ObjectDataSource (just like a typed dataset). We'll discuss the ObjectDataSource in detail in the next tutorial.


Figure III: List of products displayed in the GridView


Step Three: Add field-level validation to DataRow

Field-level validation refers to checking all the property values involved in a business object when inserting or updating. Take the product for example, some field-level validation rules are as follows:

· ProductName field must not exceed 40 characters

· QuantityPerUnit field must not exceed 20 characters

· ProductID, ProductName, and discontinued fields are required and other fields can be filled out.

· UnitPrice, UnitsInStock, UnitsOnOrder, and ReorderLevel fields must not be less than 0

These rules can or should be described in the database layer. The number of characters on the ProductName and QuantityPerUnit fields can be achieved by the data type of the corresponding column in the Products table (nvarchar and nvarchar (20) respectively). The field "required" can be implemented by setting the corresponding column of the table in the database to allow null. To ensure that the values of the UnitPrice, UnitsInStock, UnitsOnOrder, and ReorderLevel fields are not less than 0, you can add a constraint to their respective columns.

In addition to applying these rules to the database, they are also applied to the dataset. In fact, information such as field length and whether it is allowed to be empty has been applied to the DataColumn collection of each DataTable. We can see the field-level validation that already exists in the DataSet Designer (Designer), select a field from a DataTable, and then find it in the Properties window. As shown in Figure four, the QuantityPerUnit field in productdatatable allows null values and a maximum length of 20 characters. If we try to set a string that is longer than 20 characters for a Productsdatarow QuantityPerUnit property, a ArgumentException is thrown.


Figure IV: DataColumn provides basic field-level validation


Unfortunately, we cannot specify a boundary check through the Properties window, such as the UnitPrice value cannot be less than 0. To provide such field-level validation, we need to create an event Handler for the ColumnChanging event in the DataTable. As mentioned in the previous tutorial, datasets, DataTable, and DataRow objects created by typed datasets can be extended by partial classes. Using this technique, we can create a columnchanging event Handler for productdatatable. Let's start by creating a new class file named ProductsDataTable.ColumnChanging.cs in the App_Code folder, as shown in the following illustration.


Figure five: Adding a new class in the App_Code folder


Then, create an event handler for the ColumnChanging event to ensure that the values of UnitPrice, UnitsInStock, UnitsOnOrder, and ReorderLevel fields are not less than 0. If the values of these columns are out of range, a ArgumentException is thrown.

ProductsDataTable.ColumnChanging.cs

1public Partial class Northwind
2{
3 Public partial class Productsdatatable
4 {
5 public override void BeginInit ()
6 {
7 this. ColumnChanging + = Validatecolumn;
8}
9
Ten void Validatecolumn (object sender, DataColumnChangeEventArgs e)
11 {
The E.column.equals (this. Unitpricecolumn))
13 {
if (! Convert.isdbnull (e.ProposedValue) && (decimal) e.ProposedValue < 0)
15 {
throw new ArgumentException ("UnitPrice cannot be less than zero", "UnitPrice");
17}
18}
The else if (e.column.equals) (this. Unitsinstockcolumn) | |
E.column.equals (this. Unitsonordercolumn) | |
E.column.equals (this. Reorderlevelcolumn))
22 {
if (! Convert.isdbnull (e.ProposedValue) && (short) e.ProposedValue < 0)
24 {
throw new ArgumentException (string. Format ("{0} cannot be less than zero", e.column.columnname), e.column.columnname);
26}
27}
28}
29}
30}
Step Fourth: Add a business rule to the BLL class

In addition to field-level validation, there may be more advanced business rules that contain different entities or concepts that cannot be represented in a single column, such as:

· If a product is marked as "inactive," its unit price cannot be modified

· An employee's place of residence must be the same as the residence of his/her supervisor

· If a product is the only product provided by a vendor, then the product cannot be marked as "inactive"

The BLL class should ensure that the application's business rules are always validated. These validations can be added directly to the method in which they are applied.

Imagine that our business rules show that if a product is the only product of a given vendor, it cannot be marked as deactivated. In other words, if product X is the only product we buy from supplier Y, then we can't Mark X as inactive, but if supplier Y provides us with a total of 3 products, A, B, and C, then we can mark any one or three of them as "inactive." Pretty weird business rules, huh? But the business rules are usually different from what we normally feel.

To apply this business rule to the Updateproducts method, we should first check whether the discontinued is set to true. If so, then we should call Getproductsbysupplierid first to see how many products we have purchased from this vendor altogether. If we buy this product only from this supplier, then we throw a applicationexception.

UpdateProduct

1public bool UpdateProduct (string productName, int? supplierID, int? CategoryID, String QuantityPerUnit,
2 decimal UnitPrice, short? UnitsInStock, short? UnitsOnOrder, short? ReorderLevel,
3 bool discontinued, int ProductID)
4{
5 Northwind.productsdatatable products = Adapter.getproductbyproductid (ProductID);
6 if (products. Count = 0)
7//No match found, return false
8 return false;
9
Northwind.productsrow product = Products[0];
11
12//Business rule Check – cannot deactivate the only product provided by a vendor
if (discontinued)
14 {
15//Get all the products we get from this Supplier
Northwind.productsdatatable productsbysupplier = Adapter.getproductsbysupplierid (product. SupplierID);
17
if (Productsbysupplier.count = 1)
19//This is the only product we get from this Supplier
throw new ApplicationException ("You cannot mark a product as discontinued if it's only product purchased from a supp Lier ");
21}
22
Product. ProductName = ProductName;
-if (SupplierID = null) product. Setsupplieridnull (); else product. SupplierID = Supplierid.value;
if (CategoryID = null) product. Setcategoryidnull (); else product. CategoryID = Categoryid.value;
-if (QuantityPerUnit = null) product. Setquantityperunitnull (); else product. QuantityPerUnit = QuantityPerUnit;
/if (UnitPrice = null) product. Setunitpricenull (); else product. UnitPrice = Unitprice.value;
The IF (UnitsInStock = null) product. Setunitsinstocknull (); else product. UnitsInStock = Unitsinstock.value;
if (UnitsOnOrder = = null) product. Setunitsonordernull (); else product. UnitsOnOrder = Unitsonorder.value;
if (ReorderLevel = null) product. Setreorderlevelnull (); else product. ReorderLevel = Reorderlevel.value;
to product. Discontinued = discontinued;
32
33//More new product record
int rowsaffected = adapter.update (product);
35
36///If just one record is updated, returns True, otherwise returns false
Notoginseng return rowsaffected = = 1;
38}
39
   responding to validation errors in the presentation layer

When we call BLL from the presentation layer, we can decide whether to handle an exception that might be thrown or throw it directly to asp.net (this will cause an HttpApplication error event). When using BLL, if you want to handle an exception programmatically, we can use the Try...catch block, just like the following example:

1 PRODUCTSBLL productlogic = new PRODUCTSBLL ();
2
3//Update ProductID 1 Product Information
4 Try
5 {
6//This operation will fail because we are trying to use a UnitPrice less than 0
7 productlogic.updateproduct ("Scott's Tea", 1, 1, NULL, -14M, ten, NULL, NULL, FALSE, 1);
8}
9 catch (ArgumentException AE)
10 {
One Response.Write ("There was a problem:" + AE. message);
12}
As we'll see later in the tutorial, when you insert, modify, or delete operational data through a data Web control, the handling of exceptions thrown from BLL can be done directly in an event handler without the need to use a try ... Catch block to wrap the code.

   Summary

An application with a good architecture has a clear hierarchy, and each layer encapsulates a specific role. In the first installment of this tutorial, we created a data access layer with a typed dataset; In this article, we set up a business logic layer that consists of a series of classes in the App_Code and calls the corresponding methods in the DAL. BLL implements the field-level and business-level logic for our applications. In addition to creating a separate BLL, as we have done in this section, another option is to use the partial class to extend the methods in TableAdapter. However, using this technique does not allow us to rewrite existing methods or to separate our Dal and BLL from clear enough.

After the Dal and BLL are finished, we are ready to start processing the presentation layer. In the next tutorial, we will briefly introduce some data access topics and define a consistent page rendering for the entire tutorial.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.