ビジネス ロジック層を作成する (C#)
このチュートリアルでは、プレゼンテーション 層と DAL 間のデータ交換の仲介役となるビジネス ロジック レイヤー (BLL) にビジネス ルールを一元化する方法について説明します。
はじめに
最初のチュートリアルで作成されたデータ アクセス層 (DAL) は、データ アクセス ロジックとプレゼンテーション ロジックを完全に分離します。 ただし、DAL はプレゼンテーション層からデータ アクセスの詳細をクリーンに分離しますが、適用される可能性のあるビジネス ルールは適用されません。 たとえば、アプリケーションでは、フィールドが 1 に設定されている場合Discontinued
にテーブルの Products
フィールドまたは SupplierID
フィールドを変更できないようにCategoryID
したり、従業員が後で雇用された人によって管理される状況を禁止したり、年功序列ルールを適用したりできます。 もう 1 つの一般的なシナリオは、特定のロールのユーザーのみが製品を削除したり、値を UnitPrice
変更したりできる承認です。
このチュートリアルでは、プレゼンテーション 層と DAL 間のデータ交換の仲介役となるビジネス ロジック レイヤー (BLL) にこれらのビジネス ルールを一元化する方法について説明します。 実際のアプリケーションでは、BLL を別のクラス ライブラリ プロジェクトとして実装する必要があります。ただし、これらのチュートリアルでは、プロジェクト構造を簡略化するために、フォルダーに App_Code
一連のクラスとして BLL を実装します。 図 1 は、プレゼンテーション 層、BLL、DAL 間のアーキテクチャ関係を示しています。
図 1: BLL はプレゼンテーション層をデータ アクセス層から分離し、ビジネス ルールを適用する
手順 1: BLL クラスの作成
BLL は、DAL の TableAdapter ごとに 1 つずつ、4 つのクラスで構成されます。これらの各 BLL クラスには、DAL 内のそれぞれの TableAdapter から取得、挿入、更新、削除を行い、適切なビジネス ルールを適用するためのメソッドが用意されています。
DAL 関連クラスと BLL 関連のクラスをよりクリーンに分離するには、 フォルダーと に 2 つのサブフォルダー DAL
BLL
をApp_Code
作成しましょう。 ソリューション エクスプローラー内のフォルダーをApp_Code
右クリックし、[新しいフォルダー] を選択するだけです。 これら 2 つのフォルダーを作成した後、最初のチュートリアルで作成した Typed DataSet をサブフォルダーに DAL
移動します。
次に、サブフォルダーに 4 つの BLL クラス ファイルを BLL
作成します。 これを行うには、サブフォルダーを右クリックし、[新しい項目の BLL
追加] を選択し、[クラス] テンプレートを選択します。 4 つのクラスProductsBLL
に、、、CategoriesBLL
SuppliersBLL
および という名前を付けますEmployeesBLL
。
図 2: フォルダーに 4 つの新しいクラスを追加するApp_Code
次に、各クラスにメソッドを追加して、最初のチュートリアルの TableAdapters に対して定義されているメソッドをラップしてみましょう。 現時点では、これらのメソッドは DAL に直接を呼び出すだけです。後で戻り、必要なビジネス ロジックを追加します。
注意
Visual Studio Standard Edition 以降を使用している場合 (つまり、Visual Web Developer を使用していない場合)、必要に応じてクラス Designerを使用してクラスを視覚的に設計できます。 Visual Studio のこの新機能の詳細については、「クラス Designer ブログ」を参照してください。
クラスでは、 ProductsBLL
合計 7 つのメソッドを追加する必要があります。
GetProducts()
すべての製品を返しますGetProductByProductID(productID)
は、指定された製品 ID を持つ製品を返しますGetProductsByCategoryID(categoryID)
指定したカテゴリのすべての製品を返しますGetProductsBySupplier(supplierID)
指定したサプライヤーからすべての製品を返しますAddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued)
渡された値を使用して新しい製品をデータベースに挿入します。は、ProductID
新しく挿入されたレコードの値を返しますUpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID)
は、渡された値を使用してデータベース内の既存の製品を更新します。は、true
正確に 1 行が更新された場合は を返し、false
それ以外の場合は を返します。DeleteProduct(productID)
指定した製品をデータベースから削除します
ProductsBLL.cs
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)
{
// Create a new ProductRow instance
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;
// Add the new product
products.AddProductsRow(product);
int rowsAffected = Adapter.Update(products);
// Return true if precisely one row was inserted,
// otherwise 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)
// no matching record found, return 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;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated,
// otherwise false
return rowsAffected == 1;
}
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteProduct(int productID)
{
int rowsAffected = Adapter.Delete(productID);
// Return true if precisely one row was deleted,
// otherwise false
return rowsAffected == 1;
}
}
データ GetProducts
、GetProductByProductID
GetProductsByCategoryID
および GetProductBySuppliersID
を単に返すメソッドは、DAL を呼び出すだけで非常に簡単です。 一部のシナリオでは、このレベルで実装する必要があるビジネス ルール (現在ログオンしているユーザーやユーザーが属するロールに基づく承認規則など) が存在する場合がありますが、これらのメソッドはそのままにします。 これらのメソッドでは、BLL は、プレゼンテーション 層がデータ アクセス層から基になるデータにアクセスするプロキシとして機能します。
メソッドと UpdateProduct
メソッドはAddProduct
どちらも、さまざまな製品フィールドの値をパラメーターとして受け取り、新しい製品を追加するか、既存の製品を更新します。 テーブルの列のProduct
多くは値 (CategoryID
、、SupplierID
、 UnitPrice
を受け取っていくつかの名前を付けることができます) を受け取NULL
ることができるため、このような列にマップされる および UpdateProduct
の入力パラメーターAddProduct
は null 許容型を使用します。 Null 許容型は .NET 2.0 の新しいものであり、値型を にするかどうかを示す手法を null
提供します。 C# では、 型の後に ( などint? x;
) を追加することで、値型に null 許容型としてフラグを設定?
できます。 詳細については、「C# プログラミング ガイド」の「Null 許容型」セクションを参照してください。
3 つのメソッドはすべて、操作によって影響を受ける行が発生しない可能性があるため、行が挿入、更新、または削除されたかどうかを示すブール値を返します。 たとえば、ページ開発者が存在しない製品の を渡す を呼び出したDeleteProduct
場合、DELETE
データベースに対して発行された ステートメントは影響を受けないため、 メソッドは をDeleteProduct
返しますfalse
。ProductID
新しい製品を追加したり、既存の製品を更新したりする場合、インスタンスを受け入れるのではなく、新しい製品または変更された製品のフィールド値をスカラーのリストとして取り込みます ProductsRow
。 この方法は、クラスが既定のProductsRow
パラメーターなしのコンストラクターを持たない ADO.NET DataRow
クラスから派生しているために選択されました。 新 ProductsRow
しいインスタンスを作成するには、まずインスタンスを ProductsDataTable
作成してから、その NewProductRow()
メソッドを呼び出す必要があります (これは で AddProduct
行います)。 この欠点は、ObjectDataSource を使用して製品の挿入と更新を行うときに頭を後回しします。 つまり、ObjectDataSource は入力パラメーターのインスタンスの作成を試みます。 BLL メソッドがインスタンスを ProductsRow
予期している場合、ObjectDataSource はインスタンスを作成しようとしますが、既定のパラメーターなしのコンストラクターがないため失敗します。 この問題の詳細については、次の 2 つの ASP.NET フォーラムの投稿を参照してください: Strongly-Typed DataSet を使用した ObjectDataSources の更新、 ObjectDataSource と dataSet の問題 Strongly-Typed。
次に、 と の両方AddProduct
で、インスタンスをProductsRow
作成し、渡したばかりの値を設定UpdateProduct
します。 DataRow の DataColumns に値を割り当てると、さまざまなフィールド レベルの検証チェックが行われる可能性があります。 したがって、渡された値を DataRow に手動で戻すと、BLL メソッドに渡されるデータの有効性が保証されます。 残念ながら、Visual Studio によって生成される厳密に型指定された DataRow クラスでは、null 許容型は使用されません。 むしろ、DataRow 内の特定の DataColumn がデータベース値に対応していることを示すには NULL
、 メソッドを SetColumnNameNull()
使用する必要があります。
では UpdateProduct
、最初に を使用して GetProductByProductID(productID)
更新するために製品を読み込みます。 これはデータベースへの不要な旅行のように思えるかもしれませんが、この余分な旅行は、オプティミスティックコンカレンシーを探索する将来のチュートリアルで価値があることを証明します。 オプティミスティック コンカレンシーは、同じデータで同時に作業している 2 人のユーザーが誤って互いに変更を上書きしないようにする手法です。 また、レコード全体を取得すると、DataRow の列のサブセットのみを変更する更新メソッドを BLL に簡単に作成できます。 クラスを SuppliersBLL
調べるときに、このような例が表示されます。
最後に、クラスに DataObject 属性が適用されており ProductsBLL
([System.ComponentModel.DataObject]
ファイルの先頭付近にあるクラス ステートメントの直前の構文)、メソッドに DataObjectMethodAttribute 属性があることに注意してください。 属性は、クラスを ObjectDataSource コントロールへのバインドに適したオブジェクトとしてマークしますDataObjectMethodAttribute
が、 は DataObject
メソッドの目的を示します。 今後のチュートリアルで説明するように、ASP.NET 2.0 の ObjectDataSource を使用すると、クラスからデータに宣言的にアクセスしやすくなります。 ObjectDataSource のウィザードでバインドできるクラスの一覧をフィルター処理するために、既定では としてマークされた DataObjects
クラスのみがウィザードのドロップダウン リストに表示されます。 クラスは ProductsBLL
、これらの属性なしでも同様に機能しますが、追加すると、ObjectDataSource のウィザードで操作しやすくなります。
その他のクラスの追加
クラスが ProductsBLL
完了したら、カテゴリ、サプライヤー、従業員を操作するためのクラスを追加する必要があります。 上の例の概念を使用して、次のクラスとメソッドを作成します。
CategoriesBLL.cs
GetCategories()
GetCategoryByCategoryID(categoryID)
SuppliersBLL.cs
GetSuppliers()
GetSupplierBySupplierID(supplierID)
GetSuppliersByCountry(country)
UpdateSupplierAddress(supplierID, address, city, country)
EmployeesBLL.cs
GetEmployees()
GetEmployeeByEmployeeID(employeeID)
GetEmployeesByManager(managerID)
注目に値する 1 つのメソッドは、 SuppliersBLL
クラスの UpdateSupplierAddress
メソッドです。 このメソッドは、仕入先の住所情報のみを更新するためのインターフェイスを提供します。 内部的には、このメソッドは、指定された supplierID
(を使用してGetSupplierBySupplierID
) オブジェクトを読み取SupplierDataRow
り、そのアドレス関連のプロパティを設定してから、 の メソッドをSupplierDataTable
Update
呼び出します。 メソッドは UpdateSupplierAddress
次のとおりです。
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateSupplierAddress
(int supplierID, string address, string city, string country)
{
Northwind.SuppliersDataTable suppliers =
Adapter.GetSupplierBySupplierID(supplierID);
if (suppliers.Count == 0)
// no matching record found, return false
return false;
else
{
Northwind.SuppliersRow supplier = suppliers[0];
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;
// Update the supplier Address-related information
int rowsAffected = Adapter.Update(supplier);
// Return true if precisely one row was updated,
// otherwise false
return rowsAffected == 1;
}
}
BLL クラスの完全な実装については、この記事のダウンロードを参照してください。
手順 2: BLL クラスを使用して型指定されたデータセットにアクセスする
最初のチュートリアルでは、プログラムで Typed DataSet を直接操作する例を見ましたが、BLL クラスを追加すると、プレゼンテーション層は代わりに BLL に対して機能する必要があります。 最初のチュートリアルの AllProducts.aspx
例では、 ProductsTableAdapter
を使用して、次のコードに示すように、製品の一覧を GridView にバインドしました。
ProductsTableAdapter productsAdapter = new ProductsTableAdapter();
GridView1.DataSource = productsAdapter.GetProducts();
GridView1.DataBind();
新しい BLL クラスを使用するには、変更する必要があるコードの最初の行だけをオブジェクトProductBLL
にProductsTableAdapter
置き換えます。
ProductsBLL productLogic = new ProductsBLL();
GridView1.DataSource = productLogic.GetProducts();
GridView1.DataBind();
BLL クラスには、ObjectDataSource を使用して宣言型 (Typed DataSet と同様) にアクセスすることもできます。 次のチュートリアルでは、ObjectDataSource について詳しく説明します。
図 3: 製品の一覧が GridView に表示される (フルサイズの画像を表示する をクリックします)
手順 3: DataRow クラスに Field-Level 検証を追加する
フィールド レベルの検証は、挿入または更新時にビジネス オブジェクトのプロパティ値に関連するチェックです。 製品のフィールド レベルの検証規則には、次のようなものがあります。
- フィールドの
ProductName
長さは 40 文字以下にする必要があります - フィールドの
QuantityPerUnit
長さは 20 文字以下にする必要があります - 、
ProductName
、およびDiscontinued
フィールドProductID
は必須ですが、他のすべてのフィールドは省略可能です - 、、
UnitsInStock
UnitsOnOrder
、およびReorderLevel
の各フィールドはUnitPrice
、0 以上である必要があります
これらのルールは、データベース レベルで表現でき、表現する必要があります。 フィールドと フィールドのProductName
文字制限は、テーブル内の列Products
のデータ型 (nvarchar(40)
および nvarchar(20)
) によってキャプチャQuantityPerUnit
されます。 データベース テーブルの列で が許可 NULL
されている場合、フィールドが必須で省略可能かどうかが で表されます。 4 つのチェック制約が存在し、0 以上の値のみが、、UnitsInStock
、UnitsOnOrder
または ReorderLevel
列に変換UnitPrice
できるようにします。
これらの規則をデータベースに適用するだけでなく、DataSet レベルでも適用する必要があります。 実際、フィールドの長さと値が必須か省略可能かは、DataTable の DataColumns の各セットに対して既にキャプチャされています。 既存のフィールド レベルの検証が自動的に提供されるのを確認するには、DataSet Designerに移動し、DataTables の 1 つからフィールドを選択し、プロパティ ウィンドウに移動します。 図 4 に示すように、 の QuantityPerUnit
ProductsDataTable
DataColumn の最大長は 20 文字で、値は許可 NULL
されます。 の QuantityPerUnit
プロパティを ProductsDataRow
20 文字を超える文字列値に設定しようとすると、 ArgumentException
がスローされます。
図 4: DataColumn は基本的な Field-Level 検証を提供します (フルサイズの画像を表示するには、ここをクリックします)
残念ながら、プロパティ ウィンドウを使用して、値が UnitPrice
0 以上である必要があるなどの境界チェックを指定することはできません。 この種類のフィールド レベルの検証を提供するには、DataTable の ColumnChanging イベントのイベント ハンドラーを作成する必要があります。 前のチュートリアルで説明したように、型指定された DataSet によって作成された DataSet、DataTables、および DataRow オブジェクトは、部分クラスを使用して拡張できます。 この手法を使用して、 クラスの ColumnChanging
イベント ハンドラーを ProductsDataTable
作成できます。 まず、 という名前ProductsDataTable.ColumnChanging.cs
のフォルダーに クラスをApp_Code
作成します。
図 5: フォルダーに新しいクラスを App_Code
追加する (フルサイズの画像を表示する] をクリックします)
次に、 イベントのイベント ハンドラーをColumnChanging
作成して、、および ReorderLevel
列の値 (そうでないNULL
場合) が 0 以上であることを確認UnitPrice
UnitsInStock
UnitsOnOrder
します。 このような列が範囲外の場合は、 をスローします ArgumentException
。
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);
}
}
}
}
}
手順 4: BLL のクラスにカスタム ビジネス ルールを追加する
フィールド レベルの検証に加えて、次のような単一列レベルでは表現できないさまざまなエンティティや概念を含む高レベルのカスタム ビジネス ルールが存在する場合があります。
- 製品が廃止された場合、その
UnitPrice
製品は更新できません - 従業員の居住国は、上司の居住国と同じである必要があります
- サプライヤーが提供する唯一の製品である場合、製品を中止することはできません
BLL クラスには、アプリケーションのビジネス ルールへの準拠を確認するためのチェックが含まれている必要があります。 これらのチェックは、適用先のメソッドに直接追加できます。
特定のサプライヤーからの唯一の製品である場合、製品を廃止とマークできなかったことがビジネス ルールで規定されていることを想像してください。 つまり、製品 X がサプライヤー Y から購入した唯一の製品である場合、 X を廃止済みとしてマークすることはできません。ただし、サプライヤー Y から A、 B、 C の 3 つの製品が提供された場合は、これらすべてを廃止としてマークできます。 奇妙なビジネス ルールですが、ビジネス ルールと常識が常に一致するとは限りません。
メソッドでこのビジネス ルールを UpdateProducts
適用するには、 が Discontinued
に true
設定されているかどうかを確認することから始めます。設定されている場合は、 を呼び出 GetProductsBySupplierID
して、この製品のサプライヤーから購入した製品の数を決定します。 このサプライヤーから購入した製品が 1 つだけの場合は、 をスローします ApplicationException
。
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)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
// Business rule check - cannot discontinue
// a product that is supplied by only
// one supplier
if (discontinued)
{
// Get the products we buy from this supplier
Northwind.ProductsDataTable productsBySupplier =
Adapter.GetProductsBySupplierID(product.SupplierID);
if (productsBySupplier.Count == 1)
// this is the only product we buy from this supplier
throw new ApplicationException(
"You cannot mark a product as discontinued if it is 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;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated,
// otherwise false
return rowsAffected == 1;
}
プレゼンテーション層での検証エラーへの対応
プレゼンテーション層から BLL を呼び出すときに、発生する可能性のある例外を処理するか、(イベントを発生HttpApplication
Error
させる) ASP.NET までバブルアップさせるかを決定できます。 プログラムで BLL を操作するときに例外を処理するには、 try... を使用します。次 の例に示すように、catch ブロック。
ProductsBLL productLogic = new ProductsBLL();
// Update information for ProductID 1
try
{
// This will fail since we are attempting to use a
// UnitPrice value less than 0.
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);
}
今後のチュートリアルで説明するように、データ Web コントロールを使用してデータの挿入、更新、または削除を行うときに BLL からバブル アップする例外を処理することは、ブロックでコードをラップするのではなく、イベント ハンドラーで try...catch
直接処理できます。
まとめ
適切に設計されたアプリケーションは、それぞれ特定のロールをカプセル化する個別のレイヤーに作成されます。 この記事シリーズの最初のチュートリアルでは、型指定されたデータセットを使用してデータ アクセス層を作成しました。このチュートリアルでは、DAL を呼び出すアプリケーションのフォルダー内の一連の App_Code
クラスとしてビジネス ロジック レイヤーを構築しました。 BLL は、アプリケーションのフィールド レベルおよびビジネス レベルのロジックを実装します。 このチュートリアルで行ったように、別の BLL を作成するだけでなく、部分クラスを使用して TableAdapters のメソッドを拡張することもできます。 ただし、この手法を使用しても、既存のメソッドをオーバーライドすることも、DAL と BLL をこの記事で取り上げられたアプローチと同じようにきれいに分離することもできません。
DAL と BLL が完了したら、プレゼンテーション レイヤーから開始する準備ができました。 次の チュートリアル では、データ アクセス トピックから簡単に迂回し、チュートリアル全体で使用するための一貫したページ レイアウトを定義します。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Liz Shulok、Dennis Patterson、Carlos Santos、および Hilton Giesenow でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示