PDA

View Full Version : آموزش: مقاله: پیاده سازی و ساخت DataAccessLayer (معماری چندلایه دسترسی به داده) در قالب یک پروژه



alonemm
چهارشنبه 05 بهمن 1390, 16:12 عصر
باسلام:
در این مقاله آموزشی میخوام پیاده سازی و ساخت DataAccessLayer (معماری چندلایه دسترسی به داده) در قالب یک پروژه آموزش بدم.

هدف:
پاسخ گویی و راهنمایی برای تمامی کاربران که مدتی هست که در این راستا سوالات زیادی مطرح میکنند و پی گیری تمایمی سوالات در این تاپیک.


پایگاه داده انتخاب شده: SQLServer 2008
ورژن دات نت : 4
فضای نام:

using System.Data.SqlClient;
using System.Data;



پاورقی:
دوستان لطفا از پست اضافی پرهیز کنید که تاپیک بهره بیشتری داشته باشه.

alonemm
چهارشنبه 05 بهمن 1390, 16:23 عصر
توضیح مختصر:
در معماری چندلایه ما از دسترسی به صورت مستقیم در قسمت کد صفحه فرم مون به پایگاه داده جلوگیری میکنیم.
ما کلیه این عملیات رو توسط یک کلاس واست که میتونه یک فایل DLL باشه انجام بدیم و خودمون رو درگیر تعریف اشیای کار با پایگاه داده نکنیم و از درستی کلیه متدها مطمعنیم و در هر پروژه ای میتونیم ازش استفاده کنیم که این یک کلاس واسط هست که متدها و اشیای کاربا بانک اطلاعاتی داخلش هست که DataAccessLayer نامیده میشه.

خب در این قسمت میخوایم DataAccesLayer رو بسازیم:
یک پروژه از نوع ClassLibrary میسازیم با نام DataAccesLayer.
این پروژه دارای یک خروجی از جنس DLL میباشد.
یک فایل کلاس به پروژه اضافه کنید و اسمش رو ADO بزارید.
خب حالا در این کلاس شروع میکنیم به تعریف اشیا و متدهای کار با پایگاه داده:

alonemm
چهارشنبه 05 بهمن 1390, 16:35 عصر
public sealed class ADO
{


#region Attribute

private SqlConnection _conn;

#endregion

#region Properties

public string Strcon { get; set; }

public SqlConnection conn
{
get
{
return _conn;
}
set
{
_conn = value;
}
}

در کدهای بالا ما در کلاس یک شی اتصال به پایگاه داده SQLServer و 2 خواص تعریف کردیم.

public ADO()
{
conn = new SqlConnection(Strcon);
}

public ADO(string Strconnection)
{
Strcon = Strconnection;
conn = new SqlConnection(Strcon);
}

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

alonemm
چهارشنبه 05 بهمن 1390, 16:45 عصر
در این پست به تعریف متدها میپردازیم:

#region Method
public void OpenConn()
{
if (conn.State == ConnectionState.Closed)
conn.Open();
}

public void CloseConn()
{
if (conn.State == ConnectionState.Open)
conn.Close();
}


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




public int NonQuery(string SqlText,CommandType CMDType = CommandType.Text)
{
try
{
int res;
SqlCommand cmd = new SqlCommand(SqlText, conn);
cmd.CommandType = CMDType;
res = cmd.ExecuteNonQuery();
return res;
}
catch { return -1; }
}

از متد بالا زمانی استفاده میشه که شما بخواید یک کوئری رو اجرا کنید مثل عملیات رکورد جدید و یا ویرایش ...
پارامتر اول رشته کوئری
پارامتر دوم که به صورت اختیاری هست نوع رو مشخص میکنه که این کوئری از چه جنسی هست که به صورت ثابت متن هستش.



public DataTable Select(string SqlText,CommandType CMDType = CommandType.Text)
{
try
{
SqlCommand cmd = new SqlCommand(SqlText, conn);
cmd.CommandType = CMDType;
SqlDataReader sdr;
sdr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(sdr);
return dt;
}
catch { return null; }
}

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


public SqlDataReader SelectDR(string SqlText, CommandType CMDType = CommandType.Text)
{
try
{
SqlCommand cmd = new SqlCommand(SqlText, conn);
cmd.CommandType = CMDType;
SqlDataReader sdr;
sdr = cmd.ExecuteReader();
return sdr;
}
catch { return null; }
}

این متد جنس بازگشتی DataReader هست و پارامترها مشخص شده قبلا.



public bool Where(string SqlText, CommandType CMDType = CommandType.Text)
{
try
{
bool rs = false;
SqlCommand cmd = new SqlCommand(SqlText, conn);
cmd.CommandType = CMDType;
SqlDataReader sdr;
sdr = cmd.ExecuteReader();
if (sdr.HasRows == true)
{
rs = true;
return rs;
}
else
{
return rs;
}
}
catch { return false; }
}
#endregion

از این متد برای آگاهی از وجود یک رکورد استفاده میکنیم.

alonemm
چهارشنبه 05 بهمن 1390, 16:50 عصر
خب پیاده سازی اشیا و متدها به پایان رسید.
حالا پروژه رو Build کنید و در پوشه Bin->Debug فایل مربوطه با پسوند DLL رو مشاهده کنید.

خب حالا یک پروژه از نوع وب سایت میسازیم.
سپس از قسمت Solution روی اسم پروژه وب سایت کلیک راست میکنیم و قسمت AddReference را انتخاب کنید و از مسیر پوشه بالا فایل DLL مربوطه رو انتخاب کنید.
باید در پوشه bin در وبسایت شما اضافه بشه.

alonemm
چهارشنبه 05 بهمن 1390, 17:05 عصر
خب حالا در پروژه وب سایت یک کلاس نیاز داریم که توش 2 پراپرتی یا همون خواص رو تعریف کنیم.
در پوشه App_code یک کلاس به نام InheritancePage.cs میسازیم.
به صورت زیر:

#region Properties

protected DataAccess.ADO SADO
{
get
{
object value = this.Session["MySession"];
if (value != null)
return value as DataAccess.ADO;
else
return new DataAccess.ADO(GetStrConnection);
}
set
{
this.Session["MySession"] = value;
//this.ClientID +
}
}


public string GetStrConnection
{
get
{
return System.Configuration.ConfigurationManager.Connecti onStrings["DatabaseConnectionString"].ConnectionString; ;
}
}
#endregion

خواص GetStrConnection فقط خواندنی هست و کارش اینکه از فایل web.config رشته اتصال رو میخونه.
خواص SADO کارش اینکه کلاس ADO رو داخل یک سشن نگهداری میکنه و در صورت وجود نداشتن نمونه سازی میکنه.

خب حالا به سراغ فایل Global.asax میریم:
و دو متد زیر رو به شکل زیر تغییر میدیم:

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
if (Session["MySession"] == null)
{
InheritancePage INP = new InheritancePage();
Session["MySession"] = new DataAccess.ADO(INP.GetStrConnection);
}

}

void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
Session.Remove("MySession");
}

کار متد اول ذخیره سازی کلاس مربوطه در سشن در اولین بازدید کاربر و متد دوم در پایان کار کاربر با سایت شما رخ میده که سشن مربوطه رو که حاوی کلاس هست رو حذف میکنه.

alonemm
چهارشنبه 05 بهمن 1390, 17:08 عصر
یک شی گرید روی صفحه بزارید و در قسمت کد :

public partial class Default2 : InheritancePage
{
protected void Page_Load(object sender, EventArgs e)
{
SADO.OpenConn();
GridView1.DataSource = SADO.Select("select * from tbl");
GridView1.DataBind();
SADO.CloseConn();
}
}



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

alonemm
چهارشنبه 05 بهمن 1390, 17:09 عصر
بقیه متدها رو میتونید خودتون بسازید.


پایان بحث.
امیدوارم از این مقاله بهره کافی برده باشید.


از کدنویسی لذت ببرید.

dorparasti
چهارشنبه 05 بهمن 1390, 21:03 عصر
با تشکر از وقتی که گذاشتید و سعی کردید دانش خودتون رو با دیگران به اشتراک بزارید

در مورد خود استفاده از این کلاس ها ، توصیه اینه که با وجود امکاناتی مثل Entity Framework دیگه از این کلاس ها استفاده نشه . چون هم استاندارد هستند هم امن تر .

جدای از این ، چند نکته در کد شما هست :

1- می تونستید از using استفاده کنید که باعث اجتناب از باز موندن اتصال ها میشه . خیلی وقتها به علت روی دادن استثناها اتصال ها باز می مونن که با استفاده از using این مشکل برطرف می شه .
2- شما با استفاده از try catch در صورت بروز استثنا در حین اجرای کد دارید یک مقدار پیش فرض رو به لایه بالاتر می فرستید . بهتره که در این لایه استثنا ها به اصطلاح خفه نشن ( با استفاده از catch و فرستادن مقدار پیش فرض ) بلکه استثنا ایجاد و پرتاب بشه ! و در لایه های بالاتر ، شخصی که داره از این لایه استفاده می کنه بعد از مواجه با استثناها بر طبق منطق برنامه اونها رو مدیریت کنه .

این مقاله (http://www.dotnettips.info/2012/01/sqlhelper.html) رو از دست ندید

aminghaderi
چهارشنبه 05 بهمن 1390, 22:34 عصر
در مورد خود استفاده از این کلاس ها ، توصیه اینه که با وجود امکاناتی مثل Entity Framework دیگه از این کلاس ها استفاده نشه . چون هم استاندارد هستند هم امن تر .
حرف شما کاملا متین و مهندسی ولی بعضی اوقات ایجاب می کنه که قطعه ای بنویسیم که کاملا مستقل باشه و اینجاست که لازمه تا به این مقوله ها آشنا باشیم.
این مقوله ها برای بعضی از افراد ، بحث جدیدی نیست ولی مهم کار با ارزش دوستمون هست که وقت گذاشتند و آموزش تدوین کردند تا دوستانی که اطلاعاتی درباره برنامه نویسی 3 لایه که از خانواده برنامه نویسی لایه ای هست ، ندارند با این مقوله آشنا شوند.

rahmatr
چهارشنبه 05 بهمن 1390, 23:39 عصر
مشکل عمده این کلاس استفاده نکردن از Parameter (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.aspx) هاست.
بنابراین هر پروژه ای با این کلاس پیاده سازی شود هک خواهد شد.

dorparasti
چهارشنبه 05 بهمن 1390, 23:58 عصر
درسته . موافقم .
اما قسمت بد ماجرا هم همین جاست .
متأسفانه ( تا اونجا که من دیدم ) توسعه دهنده های تازه کار که باید از امکانات استاندارد استفاده کنن و با مرور زمان و کسب تجربه و سواد لازم بتونن provider های خاص و موردنیاز خودشون رو بنویسن بیشتر به علت آشنا نبودن با این امکانات و توانایی اونها میان کدهایی رو می نویسن که واقعاً خطرناکن ! ( من جمله خودم ) اونم نه برای نیازهای خاص که مثلن در provider دات نت ارائه نشده . برای کارایی که نیازی نیست . مثل ثبت و واکشی اطلاعات از دیتابیس .

rahmatr
پنج شنبه 06 بهمن 1390, 04:33 صبح
به جای استفاده از این نوع کلاسها بهتر است از Microsoft.Data (http://weblogs.asp.net/davidfowler/archive/2010/08/02/introduction-to-microsoft-data-dll.aspx) استفاده کنید :
معرفي Microsoft.Data.dll يا WebMatrix.Data.dll (http://www.dotnettips.info/2010/10/microsoftdatadll-webmatrixdatadll.html)

(برای كساني كه به هر دليلي دوست ندارند با ORMs كار كنند و از نوشتن كوئري‌هاي مستقيم SQL لذت مي‌برند.)

Saman Hashemi
پنج شنبه 06 بهمن 1390, 09:36 صبح
با تشکر از آموزش شما اما مشکلی که به نظرم رسید DLL کردن کلاس هاست که باعث میشه خوانایی پروژه از بین بره وقتی شما میتونید از کلاس استفاده کنید و این مشکلی برای شما پیش نمیاره چرا باید اینکار کرد...؟!

aminghaderi
پنج شنبه 06 بهمن 1390, 18:45 عصر
با تشکر از آموزش شما اما مشکلی که به نظرم رسید DLL کردن کلاس هاست که باعث میشه خوانایی پروژه از بین بره وقتی شما میتونید از کلاس استفاده کنید و این مشکلی برای شما پیش نمیاره چرا باید اینکار کرد...؟!
برای افزایش امنیت سورس این کار صورت می گیرد.
و لازمه زمانیکه وبسایت یا وب app رو به هاست منتقل می کنیم ، این کار رو انجام دهیم و الا در سلیشن اصلی برنامه نویس ، نباید فایل ها به صورت dll باشند ، چون دست پای برنامه نویس رو برای توسعه اون کلاس یا ... می گیرد.
البته لازمه بگم من جایی این مطلب رو نخوندم و فقط جنبه تجربی داره (تجربه خودم)، شاید جنبه علمی هم داشته باشه ولی من ندیدم.

fakhravari
پنج شنبه 06 بهمن 1390, 19:32 عصر
یه سمپل
به قول خودم 2 لایه :لبخند:

asgharzare
پنج شنبه 06 بهمن 1390, 20:02 عصر
خوب بود با تشکر

fakhravari
پنج شنبه 06 بهمن 1390, 22:45 عصر
با سلام
سمپل قبل با این روش بود string.Format
اما این سمپل روش بهتری است نسبت به قبلی > cmd.Parameters
دوستان نظر بدن

alonemm
شنبه 08 بهمن 1390, 14:44 عصر
با تشکر از وقتی که گذاشتید و سعی کردید دانش خودتون رو با دیگران به اشتراک بزارید

در مورد خود استفاده از این کلاس ها ، توصیه اینه که با وجود امکاناتی مثل Entity Framework دیگه از این کلاس ها استفاده نشه . چون هم استاندارد هستند هم امن تر .

جدای از این ، چند نکته در کد شما هست :

1- می تونستید از using استفاده کنید که باعث اجتناب از باز موندن اتصال ها میشه . خیلی وقتها به علت روی دادن استثناها اتصال ها باز می مونن که با استفاده از using این مشکل برطرف می شه .
2- شما با استفاده از try catch در صورت بروز استثنا در حین اجرای کد دارید یک مقدار پیش فرض رو به لایه بالاتر می فرستید . بهتره که در این لایه استثنا ها به اصطلاح خفه نشن ( با استفاده از catch و فرستادن مقدار پیش فرض ) بلکه استثنا ایجاد و پرتاب بشه ! و در لایه های بالاتر ، شخصی که داره از این لایه استفاده می کنه بعد از مواجه با استثناها بر طبق منطق برنامه اونها رو مدیریت کنه .

این مقاله (http://www.dotnettips.info/2012/01/sqlhelper.html) رو از دست ندید
1-استفاده از Using میتونه به حافظه کمک کنه اما در مقاله به نحوه ساخت زیاد توجه نشده و هدف فقط پیاده سازی چنین سیستم هایی هست. در مقاله بعدی قسط آموزش یک DataAccess پیشرفته رو دارم که امکاناتی از قبیل مدیریت کانکشن ها توسط خود لایه و امکان ساخت اتوماتیک کوئری ها هست.
2-دوست هر برنامه نویسی روشی برای مدیریت خطاها داره و در این کلاس هم بر اساس مقداری که بر میگرده شما میتونید تشخیص بدید که دچار مشکل هست یا خیر در DataAccess های کاملتر یک قسمت به نام Log وجود داره که تمامی خطاها رو در یک جدول از پایگاه داده ذخیره میکنه و به همین صورت در برنامه عمل میکنه.

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


موفق باشید.

alonemm
شنبه 08 بهمن 1390, 14:59 عصر
مشکل عمده این کلاس استفاده نکردن از Parameter (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.aspx) هاست.
بنابراین هر پروژه ای با این کلاس پیاده سازی شود هک خواهد شد.
دوست من همونطو که گفتم در این مقاله بیشتر به طریقه پیاده سازی مطرح شد در مقاله بعدی که بیشتر به پیاده سازی خود DataAccess پرداختم تمامی این موارد از جمله پارامترها جای داده شده هست.

alonemm
شنبه 08 بهمن 1390, 15:03 عصر
درسته . موافقم .
اما قسمت بد ماجرا هم همین جاست .
متأسفانه ( تا اونجا که من دیدم ) توسعه دهنده های تازه کار که باید از امکانات استاندارد استفاده کنن و با مرور زمان و کسب تجربه و سواد لازم بتونن provider های خاص و موردنیاز خودشون رو بنویسن بیشتر به علت آشنا نبودن با این امکانات و توانایی اونها میان کدهایی رو می نویسن که واقعاً خطرناکن ! ( من جمله خودم ) اونم نه برای نیازهای خاص که مثلن در provider دات نت ارائه نشده . برای کارایی که نیازی نیست . مثل ثبت و واکشی اطلاعات از دیتابیس .

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

alonemm
شنبه 08 بهمن 1390, 15:06 عصر
با تشکر از آموزش شما اما مشکلی که به نظرم رسید DLL کردن کلاس هاست که باعث میشه خوانایی پروژه از بین بره وقتی شما میتونید از کلاس استفاده کنید و این مشکلی برای شما پیش نمیاره چرا باید اینکار کرد...؟!

درباره منطق برنامه نویسی چندلایه کمی مطاله کنید.