# برنامه نویسی با محصولات مایکروسافت > برنامه نویسی مبتنی بر Microsoft .Net Framework > مقالات مرتبط با Microsoft .Net Framework >  ساختار چند لایه در ASP.NET2

## mahdi_negahi

سلام دوستان 

در طی این تاپیک من تصمیم دارم به معرفی معماری چند لایه که ASP.NET2 در اختیار ما میگذارد یپردازم دوستانی که در این ارتباط تجربه دارند لطفا بنده را یاری کنند تا به نتیجه مطلوب برسیم

اگر دوستان مشتاق به این تاپیک هستند لطفا این اشتیاق را نشان دهند تا بنده شروع کنم  :چشمک:  

در این تاپیک بنده طرز ساخت DAL(data access layer) و BLL(business logic layer) را در حد توان آموزش دهم البته از استادان بنده اگر مرحمتی کنند تجربیات خودشان را در اختیار ما بگذارند

----------


## mahdi_negahi

خوب برای شروغ این ورژن جدید دیتا بیس Northwind است اینو دانلود کنید تا بتونیم شروع کنیم البته باید SQL2005 داشته باشید 
البته وقتی اجراش میکنید SQL2000 میبینید  زیاد توجه نکنید

----------


## anubis_ir

Tutorial 1: Creating a Data Access Layer

http://msdn.microsoft.com/asp.net/re...sslayer_cs.asp 

Tutorial 2: Creating a Business Logic Layer
http://msdn.microsoft.com/asp.net/re...iclayer_cs.asp

----------


## mahdi_negahi

*من هم از هیمن Link ها استفاده کردم با این حال من بخش اولش میزارم اگر دوستان استقبال کردند بخش های دیگرش هم اضافه میکنم*

سلام دوستان به امید خدا این یخش اول است البته بنده سعی میکنم در حد توان زیاد به جزئیات نمی پردازم البته مفاهیمی که نیاز باشد را توضیح میدهم.
خوب اول یک پروژه ASP.NET بسازید تا شروع کنیم

اتصال به دیتابیس

در اینجا  باید شما یک اتصال به DB  خود برقرار کنید که همانطور که گفتم دیتا بیس ما از Northwind است و از SQL-Server 2005 هم استفاده میکنیم.....

در پنجره Server Explorer  روی Add New Connection  کلیک کرده و در قسمت  Server Name نام سرور خود را وارد کنید ور قسمت Select Or enter database name پایگاه داده Northwind را وارد کنید برای اطمینان روی Test connection کلیک کرده  تا از اتصال خود اطمینان داشته باشید .

مفهوم DAL(data access layer)

وقتی شما از لایه بندی در پروژه خود استفاده نمیکنید شما تمام کارهایتان در لایه presentation  انجام می دهید . منظور از لایه Presentation  همان صفحات ASP.NET هستند . ادر واقع شما با این کار لایه DAL را داخل لایهpresentation  قرار می دهید که این کار مشکلات خاص خود را دارد که عمده ترین این مشکلات به ترتیب زیر است :

1-	اگر شما 10 صفحه داشته باشد که کار با DB را انجام میدهد برای تمام این 10 صفحه باید کدهای مربوط به DB را بنویسید 
2-	تغییرات مشکل است . مثلا فرض کینید بنا به دلایلی نام یک جدول عوض میشود تصور کنید که این تغییر چقدر شما را عذاب می دهد 
البته مشکلات یک لایه کار کردن به اینجا ختم نمیشود ولی خوب خودتان دنبال این مشکلات بروید  :چشمک: 

برای رفع این مشکلات شما باید لایه Presentation و DAL را از هم جدا کنید.
تام کدهایی که به مشخص در زیر Data Source هستند مثل توابعی که کار Insert,Update و Delete ....را انجام میدهند باید در لایه DAL باشد پس یه طور کلی DAL حاوی متدهایی است که برای کار با DB مورد نیاز است.
بطور مثال در پایگاه داده ما جدولی یه نام Products و Categories وجود دارد در DAL ما متدهای با ویژگی و نامهای زیر وجود دارد (البته بخش از متدها در اینجا آورده شده است)

1-GetCategories() که اطلاعاتی درباره تمام طبقه بندی محصولات میدهد.
2-GetProducts() اطلاعاتی درباره تمام محصولات را میدهد.
GetProductByCategorieID(categorieID)-3

این متده وقتی فراخوانی میشوند به DB وصل شده و  Query مورد نظر را اجرا کرده و نتیجه را برمی گرداند. البته نوع این نتجه برگشت داده شده مهم است (type = نوع)
.این نوع میتواند یک DataSet ساده یا یک DataReader باشد.اما مطلوب ان است که نتیجه برگشتی  ازstrongly-typed objects استفاده کند
.
strongly-typed objects : نوع داده ای است که شمای آن قبل کمپایل معلوم باشد 

 loosely-typed object: این نوع داده قیل از زمان کامپایل و اجرا شمایش معلوم نیست.

به طور مثال DataReader و DataSet معمولی یک loosely-typed object هستند و برای دسترسی به یک ستون مشخص از یک loosely-typed DataTableباید از Syntax زیر استفاده کرد 
DataTable.Rows[index]["columnName"]

ولی برای دسترسی به یک ستون مشخص از strongly-typed DataTable باید از Syntax زیر استفاده کرد
DataTable.Rows[index].columnName

برای داشتن یک strongly-typed object میتونید خودتان یک کلاس تعریف کنید و بطور خاص تمام مفاهیم گفته شده را پیاده سازی کنید اما را آسانتری نیز وجود دارد که آنهم این است که Typed DataSet درست کنید که خاصیتهای بالا را داشته باشد .

در آخر هم این تصویر DAL ونحوه قرار گرفتن آن در لایه های ما است .



خوب دوستان این بخش تمام شد انشاء الله فردا بخش دوم که نحوه ساخت Typed ِDataSet است را میگویم

----------


## mahdi_negahi

سلام دوستان اینم بخش دوم امیدوارم مورد توجه قرار گیرد
*توضیح درباره typed DataSet*

Typed DataSet برای شما به وسیله Visual studio ساخته میشود و شما نیاز به کد نوشتن اضافی ندارید البته شاید این تصور راکنید که در ورژن قبلی VS، DataSet زیاد جالب نبودند ولی در ورژن 2005 روی DataSet خیلی کار شده است اگر تا آخر این تاپیک همراه ما باشید میبینید چه امکانات جالبی در اختیار برنامه نویس میگذارد .یک typed DataSet خودش تشکیل شده از کلاسهایی مانند DataTable,DataRow و همچینین چیزی که اضافه شده در دیتا ست جدید کلاسی به نام TableAdapter است که کار همان Adapter ورژن قبلی را انجام میدهد ولی با شرایطی متفاوت که خود مشاهده میکنید.

یک Typed DataSet مثلcollection of data strongly -typed  بکار می رود (معادل فارسی پیدا نکردم) . آنها ترکیب  نمونه هایی از strongly-typed DataTable که هر کدام از این نکنونه ها حاوی strongly-type DataRow هستند . ما برای هر جدول در دیتا بیس که میخواهیم روی این جداول کار کنیم یک strongly-typed DataTable  میسازیم . در ایجا ما برای جدول products میسازیم.

توجه :* strongly-typed DataTable   حاوی هیج گونه اطلاعاتی برای دستیابی به دیتاهای درون جدول متناظر خود نیست ( بطور ساده مثلا strongly-typed DataTable که برای جدول products دیتا یبس ساخته ایم نمیداند چگونه دیتا از دیتابیس وارد این strongly-typed DataTable   میشود). برای بازیابی دیتا از دیتابیس و پرکردن dataTable از TableAdapter استفاده میشود .
به طور مثال برای products DataTable ، TableAdapter حاوی متد هایی است که کار پر کردن دیتا تیبل ما را انجام می دهد نمونه ای از متد ها عبارتند از 
GetProducts()
GetProductByCategoryID(categoryID)متدها از لایه presentation صدا زده میشوند*

*ساخت یک Typed DataSet و  یک Table Adapter*

برای شروع ساخت یک DAL شما باید یک Typed DataSet به پروژه خود اضافه کنید برای این کار روی پروژه خود راست کلیک کرده و Add New Item را کلیک کنید و از صفحه باز شده DataSet  را انتخاب کنید و اسم آن را Northwind بگذارید و روی دکمه add کلیک کنید . بعد از کلیک به شما پیغام داده می شود که DataSet را در فولدر App_code اضافه شود شما این را قبول میکنید.

سپس TableAdapter Configuration Wizard  نمایان میشود شما باید اتصال به دیتا بیس که در بخش قبل ساختیم از combo Box انتخاب کنید (شکل 1) 
Next

 در صفحه بعد از شما میپرسد که مایل هستید که Connection String را به فایل Web.Config اضافه کنم که شما قبول میکنید(در این صفحه تغییری نمیدهید)

Next 


در این صفحه شما باید طریقه دستیابی به database را از این سه گزینه انخاب کنید که ما گزینه اول را انتخاب میکنیم .(شکل 2)

Next

در این صفحه باید Query اس کیو ال خود را بنوسید می توانید روی Query Bulder کیکک کنید از پنجره باز شده جدول Products را add کنید (شکل 3) و سپس روی close کلیک کرده و تمام ستونها را انتخاب کنید ( توجه برای راحتی ار انتخاب * به جای تمامه ستونها استفاده نکنید) وسپس Ok را بزنید (شکل 4) 
روی Advance Option هم کلیک کنید و مطمئن شوید که خط اول انتخاب شده

Next

این جا جالترین و جدیدترین جا است انجا را کسی در VS2003 ندیده 
در امنجا ما نام متدهای که در TableAdapter هستند را انتخاب میکنیم نام GetData را به GetAllProducts عوض کنید.(شکل 5)

تمام الان شما در App_Code/Northwind.xsd  شمایل جدول products را میبینید.این الان یک DAL بسیار ساده است که در بخشهای بعدی آن را کامل میکنیم


در بخش سوم میگویم چگونه از این چیزی که ساختید استفاده کنید

----------


## mahdi_negahi

*استفاده از DAL*
خوب دوستان حالا باید از این کاری هایی که کردیم یک استفاده کنیم خوب در یک صفحه ASP.NET یک GridView و در Page_Load صفحه تان کدهای زیر را وارد کنید

using NorthwindTableAdapters;

Page_Load

ProductsTableAdapter productsAdapter = new  ProductsTableAdapter();
GridView1.DataSource = productsAdapter.GetAllProducts();
GridView1.DataBind();حالا اجرا کنید !!! میبینید که GridView شما دیتا ها نمایش داده شده اند .همانطور که میبینید در این کد ما حتی یک کلاس از کلاسهای ADO.NET نمونه سازی نکردیم و حتی کانکشن به DataBase خود هم باز نکردیم.شما میتوانید با این کد حتی DropDownList ،CheckBoxها را هم بایند کنید .

*اضافه نمودن متدها با پارامتر ورودی DAL*

خوب تا اینجا ما DAL خود را ساخته ایم  ولی مطمئنا این DAL ما دردی از ما دوا نمیکند .در حال حاضر productsTableAdapter ما فقط یک متد دارد که آنهم تمام دیتا ها را برمیگرداند در این بخش میخواهیم متدی اضافه کنیم که با دادن ID ، Product مشخصات رکورد مورد نظر را به ما دهد خوب پس شروع کنیم.

قدم اول : 

روی فایل Northwind.xsd در فولدر App_Code کلیک کنید همانطور که در شکل میبینید شمای جدول Product را میبینید در پایین جدول در قسمت ProductTableAdapter  نام متدی که قبلا درست کردیم را میبینید روی نام متد قبلی راست کلیک کنید و از منوی باز شده Add Query را انتخاب کنید (شکل 1)

قدم دوم :

در اینجا از ما پرسیده میشود که چگونه میخواهیم دسترسی به DataBase   داشته باشید که می گزینه اول یعنی Ad hoc –Sql را انتخاب میکنیم .


قدم سوم :

صفحه نمایش داده شده را هم در قسمت قبل دیده اید. در اینجا برای سرعت کار من مستقیما SQL را می نویسم .  البته این همان دستور قبلی است با این تفاوت که این شرط Where اضافه شده : CategoryID = @CategoryID
که مقدار    @CategoryID  در زمان   اجرا مشخص میشود. .  و پارامتر ورودی تابع ما است
Next

قدم چهارم :

نام تابع را GetProductByProductID(productID)  و Finish را فشار دهید.خود VS نام پارامتر ورودی را میگذارد و شما نیازی به دادن پارامتر ورودی ندارید.

قدم پنجم:

 در فایل Northwind.xsd روی تابع بالا راست کلیک کرده و گزینه Preview Data. را انتخاب کنید و در بخش پارامتر مقداری را وارد کنید و روی Preview کلیک کنید تا دیتاها نمایش داده شود

طرز استفاده

کدهای زیر را در HTML

<body>
<form id="form1" runat="server">
<div>
<h1>Beverages</h1>
<p>
<asp:GridView ID="GridView1" runat="server"
CssClass="DataWebControlStyle">
<HeaderStyle CssClass="HeaderStyle" />
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
</asp:GridView>
&nbsp;</p>
</div>
</form>
</body>

کدهای زیر را در Code Behind:

using System.Data;
using System.Configuration;
using System.Collections;
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;
public partial class Beverages : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ProductsTableAdapter productsAdapter = new
ProductsTableAdapter();
GridView1.DataSource =
productsAdapter.GetProductsByCategoryID(1);
GridView1.DataBind();
}
}

----------


## mahdi_negahi

*اضافه،تغییر و حذف دیتاها*

به طور کلی  برای حذف ، تغییر و اضافه کردن دیتا به دیتا بیس دو روش داریم.در روش اول ما صدا میزنیم متدهای را که مستقیما روی دیتا بیس اثر گذاشته و با اجرا شدن این متدها دستورات Insetr,Update,Delete اس کیو ال هم اجرا شده و یک سطر از دیتا بیس ما تغییر میکند . این گونه متدها یک توالی از داده های یکتا دارند  (متل integer, string , DataTime) که برای انجام این اعمال لازم است.به طور مثال برای این روش برای جدول products متد Delete مقدار productsID از نوع صحیح را میگیرد و سطر متناظر این داده را پاک میکند و همچنین متد Insert یک مقدار ProductsName از نوع String و مقدار unitPrice از نوع Decimal و .... میگیرد و عمل اضافه کردن را انجام میدهد ( شکل 1)

خودتان تصور کنید بنا به دلایلی باید 10 سطر ار جدول را حذف کنید خودتان تصور کنید که این کار چقدر کسل آور است .روش دوم اشکالات این روش را  از یبن برده است.

در روش دوم یک  batch updateرا بکار میبریم .این متد در پارامتر ورودی خودش یک dataset یا datatable یا مجموعه ای از DataRow ها را میگیرد.جالب اینجاست که خود این متد تصمیم میگیرد که کدام یک از دستورات SQL یعنی INSERT, UPDATE و یا DELETE را اجرا کند.(شکل2)

یک TableAdapter به طور پیش فرض دارای یک Batch Update است .هنگاهی که ما گزینه Generate Insert , Update and Delete statement  در Advance Property انتخاب کردیم (در یخش دوم) ProductsAdapter حاوی متدی میشود به نام Update() که batch update را پیاده سازی میکند. اگر شما چک باکس GenerateDBDirectsMethod را فعال بگذارید TableAdapter شما حاوی متهای مستقیمInsert Update ,  و Delete است.

هر دوی این روش ها  استفاده میکنند ازخاصیت(property) InsertCommand و DeleteCommand و UpdateCommand، TableAdapter برای انجام اعمال اضافه کردن و حذف و تغییر در دیتا بیس.
شما میتوانید این خاصیت ها را بررسی کنید با راست کلیک روی DataSet خود در DataSet Designer و روی property کلیک کنید در پنجره می توانید این خاصیت ها را مشاهده کنید.و میتوانید حتی آنها را تغییر دهید .

*طرز استفاده*
مثال زیر را بررسی کنید
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
new NorthwindTableAdapters.ProductsTableAdapter();


Northwind.ProductsDataTable products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow product in products)
if (!product.Discontinued && product.UnitsInStock <= 25)
product.UnitPrice *= 2;
// Update the products
productsAdapter.Update(products);
اینجای کد از متدهای مستقیم استفاده میکند
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
new NorthwindTableAdapters.ProductsTableAdapter();
// Delete the product with ProductID 3
productsAdapter.Delete(3);
// Update Chai (ProductID of 1), setting the UnitsOnOrder to 15
productsAdapter.Update("Chai", 1, 1, "10 boxes x 20 bags",
18.0m, 39, 15, 10, false, 1);
// Add a new product
productsAdapter.Insert("New Product", 1, 1,
"12 tins per carton", 14.95m, 15, 0, 10, false);

----------


## mahdi_negahi

*اضافه کردن متدهای Insert,Update,Delete*

در این قسمت ما برای DAL خود متدهای Insert،Update و Delete را خودمان می سازیم
البته در این بخش ما فقط متد Insert را ساخته و متدهای بعدی به عهده خودتان باشد .
تا به حال برایتان اتفاق افتاده که وقتی یک ایتم جدیدی به دیتا بیس خود اضافه می کنید به خواهید شماره آی دی این آیتم جدید را درست بعد از اضافه کردن داشته باشید .در این بخش ما متد Insert را طوری تغییر می دهیم که نیاز ما را برآورده سازد .خوب حال شروع میکنیم .

روی Northwind.xsd کلیک کرده و در قسمت متدها راست کلیک کنید و Add Query را انتخاب کنید .

در قسمت Choose a Query type قسمت insert را انتخاب کرده و کلید Nextرا فشار دهید

همانطور که میبینید VS دستورات لازم برای اضافه کردن یک آیتم را نوشته آخر دستور یک سمی کالن(;) گذاشته و دستور زیر را اضافه میکنیم 
Select SCOP_IDENTITY
کلید  Next را فشار می دهیم .

خوب برای نام هم از نام InsetProduct استفاده کرده و Finish می زنیم.

حال روی متد در DataSet Designer راست کلیک کرده و از منوی باز شده Property را انتخاب کرده و  در قسمت ExecuteMode گزینه Scalar را انتخاب کنید . می دانید که Insert یک Query است که هیچ داده را بر نمی گرداند با این کار ما تعریف کردیم با هر فرا خوانی این متد یک مقدار برگردانده می شود که آنهم ای دی آیتم جدید است.

طرز استفاده :
  ProductsTableAdapter adap = new ProductsTableAdapter();
 int ID = Convert.ToInt32(adap.Insert("New Product", 1, 1, "12 tins  per carton", 14.95m, 10, 0, 10, false));

----------


## mahdi_negahi

*اضافه کردن جدولهای باقی مانده*
این بخش را انجام دهید چون در بخش بعدی باهاش کار داریم
با توجه به روشهای قبلی و کدهای زیر DAL خود را کامل کنید :

*•	ProductsTableAdapter*
*o	GetProducts:*
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued , (SELECT CategoryName FROM
Categories WHERE Categories.CategoryID =
Products.ProductID) as CategoryName, (SELECT CompanyName
FROM Suppliers WHERE Suppliers.SupplierID =
Products.SupplierID) as SupplierName
FROM Products

*o	GetProductsByCategoryID:*
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued , (SELECT CategoryName FROM
Categories WHERE Categories.CategoryID =
Products.ProductID) as CategoryName,
(SELECT CompanyName FROM Suppliers WHERE
Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM Products
WHERE CategoryID = @CategoryID
*o	GetProductsBySupplierID*
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued ,
(SELECT CategoryName FROM Categories WHERE
Categories.CategoryID = Products.ProductID)
as CategoryName, (SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID)
as SupplierName
FROM Products
WHERE SupplierID = @SupplierID
*o	GetProductByProductID*
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued , (SELECT CategoryName
FROM Categories WHERE Categories.CategoryID =
Products.ProductID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID)
as SupplierName
FROM Products
WHERE ProductID = @ProductID
*•	CategoriesTableAdapter
o	GetCategories*
SELECT CategoryID, CategoryName, Description
FROM Categories
*o	GetCategoryByCategoryID*
SELECT CategoryID, CategoryName, Description
FROM Categories
WHERE CategoryID = @CategoryID
*•	SuppliersTableAdapter
o	GetSuppliers*
SELECT SupplierID, CompanyName, Address, City,
Country, Phone
FROM Suppliers
*o	GetSuppliersByCountry*
SELECT SupplierID, CompanyName, Address,
City, Country, Phone
FROM Suppliers
WHERE Country = @Country
*o	GetSupplierBySupplierID*
SELECT SupplierID, CompanyName, Address,
City, Country, Phone
FROM Suppliers
WHERE SupplierID = @SupplierID
*•	EmployeesTableAdapter
o	GetEmployees*
SELECT EmployeeID, LastName, FirstName,
Title, HireDate, ReportsTo, Country
FROM Employees
*o	GetEmployeesByManager*
SELECT EmployeeID, LastName, FirstName,
Title, HireDate, ReportsTo, Country
FROM Employees
WHERE ReportsTo = @ManagerID
*o	GetEmployeeByEmployeeID*
SELECT EmployeeID, LastName, FirstName,
Title, HireDate, ReportsTo, Country
FROM Employees
WHERE EmployeeID = @EmployeeID

----------


## mahdi_negahi

*اضافه کردن کدهای دلخواه به DAL*
TableAdapter و DataTable هایی که به Typed-DataSet اضافه میشوند دارای شمای XML هستند که شما با راست کلیک در Solution Explorer  روی Northwind.xsd وانتخاب Viewcode میتوانید اکدهای XML را ببینید.
این Schema  در زمان کامپایل یا اجرا به کدهای C#‎ یا VB تبدیل می شود. برای دیدن این کدها در Class View (ctrl+shift+c) روی مثبت  NorthwindTableAdapter کلیک کنید در اینجا تمام TableAdapter هایی که تا به حال ساختید را میبینید . روی ProdouctsTableAdapter کلیک کرده و میبینید در پنجره پایین آن تمام متدها و Property ها ی این کلاس نمایش داده می شود و شما روی GetAllProduct دوبار کلیک کرده تا کدهای متناظرش را ببینید.

همانطود که گفتم این کدها را خود VS اضافه میکند حال اگر بخواهیم ما به این کدها چیزی اضافه کنیم این خطر وجود دارد که در زمان کامپایل یا اجرا این کدها دوباره تولید شده و کدهای اضافه شده ما حذف شود . تکلیف چیست ؟

برای رفع این مشکل ما از خاصیت جدیدی به نام Partial Class استفاده میکنیم.
Partial Class: این امکان را میدهد که ما کلاسهای همنام را در فایلهای مختلف یک پروژه توسعه دهیم.

برای این کار کلاس جدیدی در فولدر App_Code درست کنید و نام آن را SuppliersRow.cs 
و کدهای زیر را اضافه کنید.
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.Suppl  ierID);
}
}
}SuppliersRow نشان دهنده یک سطر از جدول Suppliers است .هر فروشنده میتواند صفر یا بیشتر محصول را تهیه کند. متد GetProducts()  نشان دهنده محصولاتی که یک فروشنده مخصوص تهیه کرده است.
این Partial Class در زمان اجرا یا کامپایل به Norhwind.SuppliersRow فضای نامی NorthwindTableAdapter اضافه میشود .(در Class view نگاه کنید)


*طرز استفاده :*
*SuppliersAndProducts.aspx*
<%@ Page Language="C#‎" AutoEventWireup="true"
CodeFile="SuppliersAndProducts.aspx.cs"
Inherits="SuppliersAndProducts" %>
<!DOCTYPE html PUBLIC "//
W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.
dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<h1> Suppliers and Their Products</h1>
<p>
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False"
CssClass="DataWebControlStyle">
<HeaderStyle CssClass="HeaderStyle" />
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
<Columns>
<asp:BoundField DataField="CompanyName"
HeaderText="Supplier" />
<asp:TemplateField HeaderText="Products">
<ItemTemplate>
<asp:BulletedList ID="BulletedList1"
runat="server" DataSource='<%#
((Northwind.SuppliersRow)((System.Data.DataRowView  )
Container.DataItem).Row).GetProducts() %>'
DataTextField="ProductName">
</asp:BulletedList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
&nbsp;</p>
</div>
</form>
</body>
</html>



*SuppliersAndProducts.aspx.cs*
using System;
using System.Data;
using System.Configuration;
using System.Collections;
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;
public partial class SuppliersAndProducts : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
SuppliersTableAdapter suppliersAdapter = new
SuppliersTableAdapter();
GridView1.DataSource = suppliersAdapter.GetSuppliers();
GridView1.DataBind();
}
}

----------


## mahdi_negahi

خوب دوستان DAL تمام شد من PDF این آموزشها را گذاشتم و اگر سوالی دارید بپرسید که در چند روز آینده BLL را شروع میکنیم

----------


## mahdi_negahi

BLL(business logic layer)


آشنایی با BLL

در آموزش قبل ما نحوه درست کردن DAL که جدا کننده لایه Presentation  از  لایه دستیابی به داده ها است را یاد گرفتیم. ولی در این لایه یعنی DAL ما هیچ گونه محدویتی های سازمانی نداریم و نمی توانیم قوانینی در کل فرایند کار با داده خود اجرا کنیم .

بطور مثال در و برای اینکه بفهمید که منظور ما چیست این مفهوم را در قالب یک مثال بیشتر توضیح می دهم.برمگردیم به جدول products شاید بنا به دلایلی ما بخواهیم اجازه تغییر فیلد CategoryID  که فیلد DisContinued آنها یک است را ندهیم این کار را نباید در DAL انجام دهیم چون DAL این وظیفه را ندارد.

یا به طور شهودی تر می خواهیم هر کسی که اعتبار سنجی شده است بتواند قدرت Delete از DataBase را داشته باشد.

به طور کل شما هر قانونی که می خواهید در Application خود اعمال کنید باید این قانون را در این لایه پیاده سازی کنید .حال میخواهد این قانون  اعمال یک سری محدویت ها در کار با پایگاه داده باشد یا نشان ندادن صفحات خاصی به کاربران.

توجه کنید که باز هم در این لایه اگر نیاز به کار با پایگاه داده دارید حتما باید از DAL کمک بگیرید.

بطور کلی این لایه واسطی بین لایه های DAL و Presentation است و بطور مستقل کار میکند .
بطور کلی شما باید این لایه را  در کلاس جداگانه ای درست کرده و البته VS  امکانی برای ساختن ساده این کلاس به شما نمی دهد و شما باید خود کد را در این بخش بنویسید .

خوب در بخش بعد روش کد نویسی این لایه را آموزش می دهم.

----------


## mahdi_negahi

طرز ساخت BLL

BLL ما تشکیل شده از 4 کلاس که هر کلاس بیانگر محدودیتهای در هر کدام از جداول TableAdapter ما هستند . هر کدام از این کلاسها حاوی متهای INSERT,Update وDelete  هستند که این متدها حاوی قوانین و سیاستهای امنیتی مورد نیاز در برنامه شما هستند .

اجازه دهید برای اینکه کدهای DAL و  BLL را از هم جدا کرده دو فلدر App_Code یه نام BLL و DLL درست کنیم و در فلدر DAL دیتا ست خود را ریخته و در BLL کلاسهای که می خواهیم درست کنیم .

خوب حالا در فلدرBLL کلاسهای اضافه کنید که هر کدام برای یکی از جداول شمادر دیتا ست است (productsBLL,CategoriesIBLL,SuppliersBLL,EmployesB  LL)

در قدم بعدی اجازه دهید اضافه کنیم برای هر کلاس متدهای برای TableAdapter بخش DAL.برای این بخش این متدها فقط از صدا میزنند بطور مستقیم المانهی DAL را و در بخش های بعدی ما اقدام به گسترش این کلاسها و پیاده سازی قوانین حاکم در این لایه می پردازیم.

برای کلاس ProductsBLL ما 7 متد اضافه میکنیم به ترتیب زیر :

•	GetProducts() 
•	GetProductByProductID(productID)
•	GetProductsByCategoryID(categoryID)
•	GetProductsBySupplier(supplierID)
•	AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice,
unitsInStock, unitsOnOrder, reorderLevel, discontinued)		
•	UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice,
unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID)
•	DeleteProduct(productID)

کد ProductsBLL

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;
    }
}در بخش بعدی توضیحی درباره این کد می دهم.

----------


## yavari

سلام

[/quote]در بخش بعدی توضیحی درباره این کد می دهم.[quote]

استاد ، توضیح بخش بعدی رو کجا دادین ، لینکشو بذارین لطفا !

ممنون

----------


## soccer player

با تشکر از مطلب خوب شما یک سوال داشتم
در روش DAL دیگر نیازی به استفاده از SqlDataSource نیست حالا اگر ما در یک GridView خاصیت Edit را فعال کنیم چه کدی باید بنویسیم تا بعد از زدن دکمه Update آن Record بتواند Update شود.
البته خارج از Gridview با استفاده از متد Update کلاس TableAdapter این کار را انجام دادم ولی در Gridview نتوانستم

باتشکر

----------


## mahdi_negahi

> توضیح بخش بعدی رو کجا دادین ، لینکشو بذارین لطفا !


دوستان بنده خیلی کار داشتم تا آخر امشب توضیح های جالبی در باره کد بالا منویسم




> در روش DAL دیگر نیازی به استفاده از SqlDataSource نیست حالا اگر ما در یک GridView خاصیت Edit را فعال کنیم چه کدی باید بنویسیم تا بعد از زدن دکمه Update آن Record بتواند Update شود.
> البته خارج از Gridview با استفاده از متد Update کلاس TableAdapter این کار را انجام دادم ولی در Gridview نتوانستم


باید از همین راه استفاده کنید شما Garidview را به صورت tempalte در بی یاورید و در رویداد RowUpdating از متد Update استفاده کنید . پیشنهاد میکنم به مقاله استادم جناب راد درباره gridview نگاهی بندازید

----------


## mahdi_negahi

این یک سمپل ساده است که خاصیت تغییر را دارد

----------


## mahdi_negahi

متدها به سادگی دیتا بر میگردانند و بصورت نسبتا مستقیم این کار را با فرخوانی DAL انجام می دهند.در حالی که در بعضی از سنارویوهای ممکن وجود داشته باشه یک سری قوانینی که شما نیاز داشته باشید و باید در اینجا آنها را پیاده سازی کنید مثل قوانین اعتیار سنجی و اینکه یک یوزر در سایت شما وارد شده یا نه.
BLL صرفا مثل یک پروکسی از میان لایه presentation دسترسی ما را به دیتاهای امکان پذیر میسازد.

تعدادی از ستونهای جداول می توانند مقدار NULL را به خود بگیرند.برای پارمترهای ورودی این ستونها در متدهای UpdateProduct و InsertProduct میتوان از نوع داده جدیدی که در .Net 2 اضافه شده استفاده کرد. این نوع داده چیزی جز nullable نیست. Nullable یک تکنیک را مهیا میکند برای اینکه مشخص کند که آیا یک مقدار میتوانند nullباشد. در C#‎ شما میتوانید با اضافه کردن ? به بعد از نوع تایپ به کامپایلر بهفهمانید که این متغییر می تواند مقدار null داشته باشد.

int? x;

تمام 3 متد ما مقداری Boolean را بر میگرداند که نشان میدهد وظیفه محمول شده را به درستی انجام داده و سطری را تحت تاثیر قرار داده یا خطایی باعث بروز اشکال شده و نتوانسته کار خود را انجام دهد. به طور مثال اگر تابع DeleteProduct را با یک شماره ID صدا بزنیم به طوری که این ID اصلا وجود نداشته باشد تابع مذکور مقدار false را برمیگرداند.

هنگاهی که میخواهیم یک محصول(product) جدید را  اضافه کنیم یا یک محصول موجود  را تغییر دهیم ما یک نمونه ProductsRow میسازیم .کلاس  ProductsRow مشتق شده از کلاس DataRow ، ADO.NET که به صورت پیش فرض از سازنده که کم پارامتر دارد استفاده میکند.به منظور ایجاد کردن یک ProductsRow جدید ، باید اول یک نمونه ProductDataTable ایجاد کرده و سپس NewProduct را فراخوانی کنید.

در کد دو متد Addproduct ,updateproduct ایجاد میکنیم  نمونه ای از ProductsRow و پر مکنیم این آبجکت را از مقدارهای فرستاده شده.هنگامی که مقادیر نسبت داده شدند به DataColumn های DataRow چک کردن فیلده اتفاق میفتد.

در stronglytyped DataRow که به وسیله ویژال دستدیو از نوع nullable استفاده نمیکند به همین خاطر ما از متدی به نام SetColumnNameNull() استفاده میکنیم

----------


## mahdi_negahi

*اعتبار سنجی Filed-Level*

اعتبار سنجی Filed-Level  وابسته است به خاصیت مقدارهایی از یک آبجکت bussines  در هنگام insert   یا update . به صورت ساده تر یعنی یک اعتبار سنجی که شما داده های ورودی را از نظر نوع و اندازه و طولشان باید چک کنید و این چک کردن فقط روی یک ستون انجام میشود . بعضی از  اعتبار سنجی Filed-Level   عبارتند از(در جدول products): 

QuantityPerUnit

•	productName که طولش باید 40 کاراکتر باشد
•	QuantityPerUnit که طولش باید حداکثر 20 کاراکتر باشد
•	productName,ProductID,DisContinued فیلدهای هستند که حتما باید پر شوند
•	UnitPrice, UnitsInStock  UnitsOnOrder و ReorderLevel  باید مقداری بیشتر یا مساوی صفر داشته باشند

این قوانین باید در سطح دیتابیس هم تعریف شده باشد مثلا اینکه طول طول فیلد productName که باید بیشتر از 40 نباشد در سطح دیتا بیس به این صورت تعریف شده Navarchar(40) واینکه فبلد productName نمیتواند null باشد alow null را برداشتیم.

در اضافه هر قانونی که در سطح دیتا بیس وجود دارد در هر جدول Dataset typed برای هر ستون اعمال میشود به طور جزئی تر اگر ستون productName  از جدول ما نباید طولش از 40 کاراکتر بیشتر باشد در typed dataset هم همینگونه است .

برای دیدن ا اعتبار سنجی Filed-Level وجود به DataSet Designer رفته و بکی از فیلدها(ستون QuantityPerUnit) را انتخاب کنید و راست کلیک کرده و گزینه property آن را انتخاب کنید . همانطور که میبینید در قسمت MaxLenght  عدد 20 و در قسمت AllowDBnull عبارت true نوشته شده است.



متاسفانه ما نمی توانیم در این قسمت اعتبار سنجی Filed-Level   خاصی اضافه کنیم  نمونه ای از این اعتبارسنجی را مثلا منفی نبودن بعضی از ستونها میتوان نام برد.برای این کار ما باید از یکی از event های DataTable به نام ColumnChanging استفاده کنیم .
خوب برای استفاده از این تکنیک ما یک event handler برای کلاس ProductsDataTable
میسازیم.

خوب برای شروع در فولدر App_Code کلاسی به نام productsDataTable.ColumnChanging.cs
به سازید.




در مرحله بعدی یک event handler برای ستونهایی جدول مورد نظر  که میخواهیم اعتبار سنجی روی آن انجام شود می سازیم 

توجه کنید که شما باید حتما حالتی را که نباید رخ دهد را تشخیص داده و تولید exeption کنید که این کار به شما کمک میکند که خطای کاربر را در لایه presentation تشخیص داده و به کاربر گوشزد کنید

توجه کنید که exeption این قسمت از نوع   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);
                }
            }
        }
    }
}شما به وسیله کد زیر یک exeption تولید میکنید 

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

و در لایه presentation شما به وسیله try و catch این execption را کنترل کنید.

----------


## mostafa_leman

آقا خسته نباشی
ادامه بده . داریم استفاده میکنیم

----------


## mahdi_farhani

سلام دوستان . دستتون درد نکنه خیلی جالب بود .
یه Sample داخل vs 2003 هست به نام duwamish توی این مثال تمام مسائل رعایت شده . خیلی کامله . هنوز امتحان نکردم ببینم تو 2005 جواب میده یا نه دوستان هم یه نگاهی بندازن و اگر میشه یه توضیح کلی در مورد این مثال بدن .

----------


## NeverFade62

سلام منبا استفاده از همین متد دارم برنامه نویسی می کنم خوب ؟
حالا وقتی می خوام برای یک توضیحات مثلا در BLL  می خوام برای یک مقدار Nvchar or text or ntext  یک مقدار در vb تعریف کنم و یا برای آرگومانم تایپ بذارم چی بذارم string  رو می گه اون تایپ نیست 
معادل این دو تایپ nvchar , ntext چیه توی VB???

----------


## xxxmmm

سلام  با تشکر از مطالب بسیار مفید شما
یه مشکلی برای من بوجود آمره می خواستم از شما سوال کنم
من یه gridview گذاشتم و از dataset استفاده کردم اما در مورد paging با مشکل برخوردم
این error پیغام رو میده
The GridView 'GridView2' fired event PageIndexChanging which wasn't handled
ممنون می شم راهنمایی کنید

----------


## amir.NET2

دوست عزیز سلام

این بخش مربوط به مقالات است

بهتر بود تو بخش ASP .NET مطرح می کردی

ولی برای حل شدن مشکلت روی رویداد PageIndexChanging گرید ویو دابل کلیک کن !!!

----------


## M.mojaddady@gmail.com

سلام
مطالبتون خیلی جالبه
ممنون که این قدر وقت می ذارین
اگه لطف کنید و ادامه بدین ممنون می شم

----------


## atakhalighi

دوستان اگر مشکل زبان ندارند میتونن برن اینجا در سایت ASP.NET و درس کامل رو مشاهده کنند.
با تشکر از mahdi_negahi بابت ترجمه مطالب.

----------


## mohebbi.saeed

ممنون از مطالبتون

----------


## el_abdollahi

میشه یکی بگه این یعنی چه؟
<System.ComponentModel.DataObjectMethodAttribute(S  ystem.ComponentModel.DataObjectMethodType.Insert, True)> _

----------


## Ghalandari

<System.ComponentModel.DataObjectMethodAttribute(S  ystem.ComponentModel.DataObjectMethodType.Insert, True)> _

این کد مشخص میکند که تابعی که در BLL قرار دارد و این کد قبل از آن قرار گرفته متدی است که به منظور Insert استفاده میشود و وقتی این BLL را به DataSource نسبت میدهیم خود DataSource تشخیص میدهد که باید از این متد به منظور Insert استفاده نماید

----------


## hitrax

سلام 
موضوع انتخابی موضوع جالبیه. اگر ادامه بدین ممنون می شم.

----------


## teshnehab

سلام دوست گرامي mehdi_negahi
اگر امکان داره pdf BLL  هم بگذاريد ،ممنون.

----------


## teshnehab

سلام جناب مهدي نگاهي
مطالبتون فوق العاده مفيد هستند ، استفاده کرديم. 
ولي بنده همان اول کار با error  متوقف شدم .تمام مراحل را همان طور که توضيح داديد طي کردم 
ولي همان چهار خط کد اولي که مي نويسم از namespace خطا مي گيره که اونو نمي شناسه.
* پيغام خطا:*
The type or namespace 'northwindTableAdapter' could not be found.

کدهاي نوشته شده:

*  using NorthwindTableAdapter;*
        ProductsTableAdapter productsAdapter = new ProductsTableAdapter();
        GridView1.DataSource = productsAdapter.GetAllProducts();
        GridView1.DataBind();

----------


## teshnehab

بابا چرا يکي راهنماي نمي کنه؟؟؟؟؟؟؟؟؟؟؟؟؟؟

----------


## mamaliy

مطلب خيلي عملي و عالي بود

----------

