WEB三层结构的设计思路

来源:互联网 发布:试卷制作软件ios 编辑:程序博客网 时间:2024/05/05 04:13

WEB三层结构的设计思路

1.DAL层的设计:

1.1.强类型的DataTable并不包括如何访问对应底层的数据表的任何信息,DataTable的作用是在分层间传输数据。要获取用来填充DataTable的


数据 ,我们使用TableAdapter类,它提供了数据访问层的功能,对于TableAdapter类中的自定义方法,我们使用部分类来保存。

 

using System;

using System.Data;

using NorthwindTableAdapters;

public partial class Northwind

{

    public partial class SuppliersRow

    {

        public Northwind.ProductsDataTable GetProducts()

        {

            ProductsTableAdapter productsAdapter = new ProductsTableAdapter();

            return productsAdapter.GetProductsBySupplierID(this.SupplierID);

        }

    }

}

 

1.2.如果使用DB直接模式,DataSet设计器会根据SELECT语句自动生成插入,更新,删除方法,而且不会受SELECT子句中的子查询的影响。但如果


使用JOIN语句的话,DataSet设计器就不能自动生成插入,更新,以及删除数据库记录的方法了,这时,必须手工设置InsertCommand,


UpdateCommand和DeleteCommand属性值.

 

SELECT     ProductID, ProductName, SupplierID, CategoryID,

QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,

(SELECT CategoryName FROM Categories

WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,

(SELECT CompanyName FROM Suppliers

WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName

FROM    Products

 

2.BLL层的设计:

2.1简单的调用DAL中的方法

 using System;

 using System.Data;

 using System.Configuration;

 using System.Web;

 using System.Web.Security;

 using System.Web.UI;

 using System.Web.UI.WebControls;

 using System.Web.UI.WebControls.WebParts;

 using System.Web.UI.HtmlControls;

 using NorthwindTableAdapters;

 

 [System.ComponentModel.DataObject]

 public class ProductsBLL

 {

     private ProductsTableAdapter _productsAdapter = null;

     protected ProductsTableAdapter Adapter

     {

         get {

             if (_productsAdapter == null)

                 _productsAdapter = new ProductsTableAdapter();

 

             return _productsAdapter;

         }

     }

 

 

 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]

     public Northwind.ProductsDataTable GetProducts()

     {       

         return Adapter.GetProducts();

     }

 

     [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]

     public Northwind.ProductsDataTable GetProductByProductID(int productID)

     {

         return Adapter.GetProductByProductID(productID);

     }

 

 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]

     public Northwind.ProductsDataTable GetProductsByCategoryID(int categoryID)

     {

         return Adapter.GetProductsByCategoryID(categoryID);

     }

 

 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]

     public Northwind.ProductsDataTable GetProductsBySupplierID(int supplierID)

     {

         return Adapter.GetProductsBySupplierID(supplierID);

     }

     [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]

     public bool AddProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,

                           decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,

                           bool discontinued)

     {

         // 新建一个ProductRow实例

         Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();

         Northwind.ProductsRow product = products.NewProductsRow();

 

         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;

         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;

         product.Discontinued = discontinued;

 

         // 添加新产品

         products.AddProductsRow(product);

         int rowsAffected = Adapter.Update(products);

 

         // 如果刚好新增了一条记录,则返回true,否则返回false

         return rowsAffected == 1;

     }

 

     [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]

     public bool UpdateProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,

                               decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,

                               bool discontinued, int productID)

     {

         Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);

         if (products.Count == 0)

             // 没有找到匹配的记录,返回false

             return false;

 

         Northwind.ProductsRow product = products[0];

 

         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;

         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;

        product.Discontinued = discontinued;

 

        // 更新产品记录

        int rowsAffected = Adapter.Update(product);

 

        // 如果刚好更新了一条记录,则返回true,否则返回false

        return rowsAffected == 1;

    }

 

    [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]

    public bool DeleteProduct(int productID)

    {

        int rowsAffected = Adapter.Delete(productID);

 

        // 如果刚好删除了一条记录,则返回true,否则返回false

        return rowsAffected == 1;

    }

}

 

 

2.2.给DataRow添加字段级验证

新建一个名为ProductsDataTable.ColumnChanging.cs的类文件

public partial class Northwind

{

    public partial class ProductsDataTable

    {

        public override void BeginInit()

         {

            this.ColumnChanging += ValidateColumn;

         }

 

         void ValidateColumn(object sender, DataColumnChangeEventArgs e)

         {

            if(e.Column.Equals(this.UnitPriceColumn))

            {

               if(!Convert.IsDBNull(e.ProposedValue) && (decimal)e.ProposedValue < 0)

               {

                  throw new ArgumentException("UnitPrice cannot be less than zero", "UnitPrice");

               }

            }

            else if (e.Column.Equals(this.UnitsInStockColumn) ||

                    e.Column.Equals(this.UnitsOnOrderColumn) ||

                    e.Column.Equals(this.ReorderLevelColumn))

            {

                if (!Convert.IsDBNull(e.ProposedValue) && (short)e.ProposedValue < 0)

                {

                    throw new ArgumentException(string.Format("{0} cannot be less than zero", e.Column.ColumnName),


e.Column.ColumnName);

                }

            }

         }

    }

}

2.3添加业务规则

public bool UpdateProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,

                              decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,

                              bool discontinued, int productID)

{

        Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);

        if (products.Count == 0)

            // 没有找到匹配项,返回false

            return false;

 

        Northwind.ProductsRow product = products[0];

 

        // 业务规则检查 – 不能停用某供应商所提供的唯一一个产品

        if (discontinued)

        {

            // 获取我们从这个供应商处获得的所有产品

            Northwind.ProductsDataTable productsBySupplier = Adapter.GetProductsBySupplierID(product.SupplierID);

 

            if (productsBySupplier.Count == 1)

                // 这是我们从这个供应商处获得的唯一一个产品

                throw new ApplicationException("You cannot mark a product as discontinued if its the only product purchased


from a supplier");

        }

 

        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;

        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;

        product.Discontinued = discontinued;

 

        // 更新产品记录

        int rowsAffected = Adapter.Update(product);

 

        // 如果刚好更新了一条记录,则返回true,否则返回false

        return rowsAffected == 1;

}

2.4在表示层中对异常的处理

那么表示层如何捕捉到异常?一种是通过try...catch()的方法,另一种就是通过WEB控件中的事件来捕捉异常。
在插入、更新或删除操作的过程中,数据Web控件和ObjectDataSource控件都包含了pre- 和post-级的事件,它们记录着当前的操作。当使用一
个可编辑的GridView时,事件触发顺序如下:ObjectDataSource_Updating-->GridView_RowUpdating-->GridView_RowUpdated--
>ObjectDataSource_Updated
我们可以为这些发生在操作之前的事件创建事件处理程序,目的是自定义输入参数;为发生在操作之后的事件创建事件处理,目的是检测和相应操作的结果。Post-level的事件处理程序通常用作侦测在操作过程中是否出现了一个异常。当面对一个异常时,这些post-level的事件处理程序可以随意地处理该异常。

示例1:

 ProductsBLL productLogic = new ProductsBLL();
 // 更新ProductID为1的产品信息
 try
 {
     // 这个操作将会失败,因为我们试图使用一个小于0的UnitPrice
     productLogic.UpdateProduct("Scott's Tea", 1, 1, null, -14m, 10, null, null, false, 1);
 }
 catch (ArgumentException ae)
 {
     Response.Write("There was a problem: " + ae.Message);
 }

示例2:
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
    if (e.Exception != null)
    {
        // Display a user-friendly message
        ExceptionDetails.Visible = true;
        ExceptionDetails.Text = "There was a problem updating the product. ";
        if (e.Exception.InnerException != null)
        {
            Exception inner = e.Exception.InnerException;
            if (inner is System.Data.Common.DbException)
                ExceptionDetails.Text += "Our database is currently experiencing problems. Please try again later.";
            else if (inner is NoNullAllowedException)
                ExceptionDetails.Text += "There are one or more required fields that are missing.";
            else if (inner is ArgumentException)
            {
                string paramName = ((ArgumentException)inner).ParamName;
                ExceptionDetails.Text += string.Concat("The ", paramName, " value is illegal.");
            }
            else if (inner is ApplicationException)ExceptionDetails.Text += inner.Message;
        }
        // Indicate that the exception has been handled
        e.ExceptionHandled = true;
        // Keep the row in edit mode
        e.KeepInEditMode = true;
    }
}

 

 总之,每个工单由3部分组成(DAL,BLL,Web),DAL和BLL都有相应有命名空间.
如工单MPR:则可以建一个NetSoft.MPR.DAL和NetSoft.MPR.BLL,然后再做一个WEB模板。这样就可以实现三层结构,而且可以使代码量较少。