TAHA
10-01-2009, 07:11 AM
با توجه به اینکه بسیاری از امکانات VS2005 برای ما نا شناخته س، لذا تصمیم بر این گرفتم که این مقاله رو که در مورد بکار گیری یکی از امکانات قدرتمند Vs2005 در برنامه نویسی دیتابیس به شمار میرود رو بنویسم :
بسیاری از ما ممکنه اسم DataSet Disgner به گوشمان خورده باشد، و یا حتی به کرات از آن در برنامه های خود استفاده کرده باشیم، ولی در مورد اینکه این ابزار چقدر میتونه ما رو در روند تولید نرم افزارهای دیتابیس کمک کنه شاید برای ما دور از تصور باشه، در این مقاله قصد بکارگیری این ابزار قدرتمند رو برای ایجاد لایه ی Data Access به شما عزیزان دارم و کاربرد اون رو طی یک پروژه ی عملی به شما نشان خواهم داد، پس بدون مقدمه ی اضافی میریم سر بحث اصلی :
پیش از شروع درس، خدمت شما عرض کنم که دیتابیس نمونه ی ما به نام TestDB میباشد که شامل یک جدول به نام Student و تعدادی رکورد است، همچنین دیتابیس ما شامل 5 Stored Procedure است که در این مقاله از آنها استفاده خواهیم کرد، پروژه ی آماده و اسکریپت T-Sql مربوط به دیتابیس رو میتوانید از انتهای همین مقاله دریافت نمایید.
همچنین، ما برای انتقال مقادیر بین فرمهای مختلف برنامه از کلاسی به نام AppDomain استفاده میکنیم، که از طریق آن، به فضای حافظه ای که برنامه ی ما در حال اجرا در داخل آن است دسترسی پیدا میکنیم، بدین صورت میتوانیم، مقادیر مورد نظر را در محدوده ای امن، در داخل فضای اختصاص داده شده به برنامه ی ما قرار دهیم و از آن در سطح کل برنامه ی خود استفاه نماییم. این کلاس دارای دو متد SetData() و GetData() میباشد که هر کدام به ترتیب برای ذخیره ی مقادیر با یک نام مشخص و گرفتن مقدار از طریق پاس کردن نام آبجکت مورد نظر مورد استفاده قرار میگیرد.
نکته ی دیگه اینکه، من برای پیچیدگی و سردرگمی کمتر، کدنویسی رو به صورت ساده انجام دادم، تا بتونم در هر قسمت از کد نویسی، توضیحات مربوطه رو بیان کنم، مثلا ممکنه در بلوک if یک آبجکت تعریف کرده باشم و در بلوک else آن نیز، همان آبجکت را با مقدار دیگری تعریف کرده باشم، این کار صرفا برای خوانایی و راحتی فهم کد انجام شده تا بتوانم هر قسمت یا بلوک رو به طور مجزا توضیح بدم، لیکن، شما میتوانید کدهای مورد نظر را بهینه نمایید.
ابتدا فایل Sql ای که ضمیمه ی مقاله شده را در Sql Server Management Studio (SSMS) اجرا کنید تا دیتابیس مورد نظر ساخته بشه، سپس شروع به خواندن ادامه ی مقاله کنید :
- پروژه ای جدید از نوع Windows Application به نام DataAccessLayer (یا هر نام دیگه ای که دوست دارید) بسازید.
- از منوی Project گزینه ی Add New Item رو کلیک کنید و یک دیتاست به برنامه اضافه نمایید.
(من نام DsTestDb رو برای دیتاستم اضافه کردم)
http://pnu-club.com/imported/2009/10/1.jpg
- مطمئن باشید که در بخش DataSet Designer هستید، در قسمت Server Explorer، به دیتابیس TestDb کانکت شوید(اگر لازم شد، Connection جدیدی بسازید).
http://pnu-club.com/imported/2009/10/2.jpg
- چون میخواهیم از بالاترین Performance در برنامه هایمان و همچنین اصولی ترین روش در تولید نرم افزارهای دیتابیس استفاده کنیم، لذا Stored Procedure ها گزینه ی مناسبی برای فرستادن فرامین T-Sql به دیتابیس است، پس در Serevr Explorer، گره Stored Procedures را Expand کنید، به صورت نمونه چند Sp برای اعمال Insert و Update و Delete ساخته شده که البته موارد دیگه هم در جای خودش بررسی میشه، sp_Student_SelectAll رو با ماوس به صورت Drag & Drop به داخل DataSet Desginer بکشید.
DataSet Designer با توجه نتیجه ی بازگشتی Sp مورد نظر، جدول Student رو برای ما میسازه، اما اگر دقت کنید چون نام جدول Student رو نمیتونه تشخیص بده، نام Sp رو به عنوان جدول Student در نظر میگیره، روی آن Double-Click کنید و به Student تغییر نام دهید.
http://pnu-club.com/imported/2009/10/3.jpg
- در زیر جدول Student، کلاسی به نام StudentTableAdapter ساخته شده، روی آن راست کلیک کنید و Configure رو انتخاب کنید.
http://pnu-club.com/imported/2009/10/4.jpg
- در قسمت Table Adapter Configuration Wizard شما بایستی برای قسمتهای مختلف Insert و Update و Delete، Sp های مربوطه رو انتخاب کنید(برای Select رو قبلا انتخاب کرده بودیم).
توجه : وقتی Sp مربوطه رو انتخاب میکنید، در سمت راست، حتما مطمئن شوید که پارامترهای آن به درستی به Source Column، Map شده باشند، در غیر اینصورت، Column صحیح رو انتخاب کنید.
http://pnu-club.com/imported/2009/10/5.jpg
- روی Next کلیک کنید و نامهای مناسبی برای متدهای مربوطه انتخاب کنید (فعلا با این قسمت کاری نداریم). Next کنید و سپس روی Finish کلیک نمایید.
اکنون TableAdapter ما از طریق Sp هایی که در دیتابیس تعریف کردیم، عملیات CRUD رو انجام میده.
پروژه تون رو Save کنید (مخصوصا صفحه ی DataSet Designer که فعال است)، با این کار Visual Studio تعداد خیلی زیادی کد رو در فایل DataSetName.Designer.cs ایجاد خواهد کرد و هر بار که تغییری در DataSet میدید، پس از ذخیره ی فایل مورد نظر، کدهای مربوطه تولید خواهند شد.
بیایید نگاهی به کد تولید شده در DataSetName.Designer.cs (و در اینجا DsTestDb.Designer.cs) بندازیم :
کلاسی به نام StudentTableAdapter که در NameSpace ای به نام DsTestDbTableAdapters ساخته شده که در دل خودش مجموعه ای از آبجکتهای SqlDataAdapter,SqlCommand,SqlConnection , … رو در برداره و کلیه ی عملیات CRUD بر روی جدول Student توسط آبجکت ساخته شده از این کلاس انجام میشه.
کلاس DsTestDb که خود شامل چند کلاس زیرمجموعه، از جمله StudentDataTable و StudentRow میباشد که StudentRow از کلاسی به نام DataRow مشتق شده که یک رکورد را در خود نگهداری میکند، تفاوت این کلاس با DataRow در این است که شما به صورت کاملا Strongly-Typed با جدول Student کار میکنید و دقیقا انواع فیلدها، همه از انواعی هستند که در دیتابیس تعریف شده اند. کلاس StudentDataTable هم که از کلاس DataTable مشتق شده و در برگیرنده ی مجموعه ای از StudentRow ها میباشد.
کلاس DsTestDb هم که از کلاس DataSet مشتق شده است.
- خب، قبل از اینکه دست به کار بشیم و شروع به نوشتن کدهای CRUD بکنیم، توصیه میکنم، کلاسی به نام Student بسازید که دارای تمام خصیصه های فیلدهای جدول Student باشه، مثل کد زیر :
public class Student
{
private int id;
private string fName;
private string lName;
public Student()
{
// do nothing
}
public int Id
{
get { return id; }
set { id = value; }
}
public string FName
{
get { return fName; }
set { fName = value; }
}
public string LName
{
get { return lName; }
set { lName = value; }
}
}
مورد استفاده این کلاس، برای راحتی کار با داده ها در زمان Insert است.
- خب، یک DataGridView به فرم اضافه کنید و در سورس کد کلاس Form1 دو آبجکت از کلاسهای زیر ایجاد کنید.
http://pnu-club.com/imported/2009/10/6.jpg
- در رویداد Form_Load آبجکت dt رو Fill کنید و DataGridView.DataSource رو بهش Bind کنید :
http://pnu-club.com/imported/2009/10/7.jpg
برنامه رو کامپایل و اجرا کنید تا اطلاعات، نمایش داده بشه. تا اینجا فقط خواندن اطلاعات رو با TableAdapter انجام دادیم و اکثرا هم این کار رو بلد هستید، اما از اینجا به بعد، یعنی عملیات تغییر داده ها رو میخواهیم با بهترین Performance انجام بدیم، خب مثل من یه Button به فرمتون اضافه کنید، میخواهیم وقتی کاربر روی این Button کلیک کرد، فرم Add New Student ظاهر بشه، پس از اضافه کردن یک Button، یک فرم هم به برنامه تون اضافه کنید با نام frmStudent و به شکل زیر طراحی کنید :
http://pnu-club.com/imported/2009/10/8.jpg
ما در دو نوبت با فرم جدیدمون (frmStudent) کار داریم، یکی زمان Insert و دیگری زمان Update، پس برای اینکه مشخص کنیم در هر زمان که به این فرم دسترسی داریم در چه وضعیتی هستیم، کد کلاس frmStudent رو به صورت زیر اصلاح میکنیم :
public partial class frmStudent : Form
{
private bool isEditMode;
public frmStudent(bool editMode)
{
InitializeComponent();
this.isEditMode = editMode;
}
}
اینطوری هر وقت بخواهیم یک آبحکت از کلاس frmStudent بسازیم تا نمایش بدیم، مشخص میکنیم که در چه وضعیتی هستیم، فعلا برای وضعیت Insert میخواهیم کدنویسی کنیم، پس در رویداد دکمه ی OK، این کد رو مینویسیم :
private void btnOK_Click(object sender, EventArgs e)
{
// create new student object from student class and set properties
Student st = new Student();
st.FName = this.txtFirstName.Text;
st.LName = this.txtLastName.Text;
// save our object to our Application Domain
// by this technique, we can transfer values between all forms
// note, the name of the object that we want to access to it via other forms is 'Student'
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", st);
// this line, pass DialogResult.OK to our form and then close it
this.DialogResult = DialogResult.OK;
}
برای دکمه ی Cancel هم میتونیم از کد زیر استفاده کنیم :
:
private void btnCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
}
- خب، حالا به Form1 برمیگردیم تا برای دکمه ی Add New Student کد زیر را بنویسیم :
private void btnAddStudent_Click(object sender, EventArgs e)
{
// create new object from frmStudent and pass false to constructor to indicate we are not in edit mode
frmStudent frm = new frmStudent(false);
if (frm.ShowDialog() == DialogResult.OK)
{
// create object from AppDomain class to retrieve our st object that pass to it via frmStudent
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
// note, we must cast it to our class
Student st = currentDomain.GetData("Student") as Student;
// create strongly-typed row from StudentRow
DsTestDb.StudentRow newRow = this.dt.NewStudentRow();
newRow.fName = st.FName;
newRow.lName = st.LName;
// add our new row to or dt
this.dt.Rows.Add(newRow);
// reflect our changes to database by applying Update command and pass our dataTable to it
this.adapter.Update(this.dt);
}
}
دقت کنید که ما برای راحتی کار از کلاس Student استفاده کردیم، وگرنه میتونستیم پس از تعریف آبجکت newRow، اون رو به frmStudent پاس بدیم و پس از بسته شدن frmStudent و برگرداندن مقدار DialogResult.OK، دوباره آبجکت مقدار دهی شده ی newRow رو بگیریم و به dt مون اضافه کنیم، اینجوری دیگه نیاز به کلاس Student نخواهیم داشت(انتخاب با خودتونه).
نکته ی دیگه اینکه در frmStudent، چون فیلد id در جدول Student در دیتابیس، به صورت identity هست، ما به اون مقدار ندادیم.
نکته ی مهم دیگه اینکه، من از DataRow برای ایجاد رکورد جدید استفاده کردم تا بتونم رکورد جدید رو مستقیما به آبجکت dt اضافه کنم، سپس، از متد TableAdapter.Update استفاده کردم تا تغییرات ایجاد شده در dt رو capture کنه و به دیتابیس منعکس کنه، اینطوری، بعد از اضافه کردن رکورد جدید، دیگه نیازی به Query مجدد از دیتابیس برای گرفتن آخرین اطلاعات نداریم مخصوصا زمانی که تعداد رکوردهای جدول زیاد باشه، و یا نرم افزار، تحت شبکه باشه، این مزیت بیشتر خودشو نشون میده و باعث میشه که بار پردازشی سرور کم بشه و همچنین از تعداد queryهای زیاد و نابجا کم بشه، در غیر اینصورت، شما با متد TableAdapter.Insert هم میتونید عمل Insert رو انجام بدید، ولی بعد از اون، باید به صورت دستی اطلاعات به روز شده رو نمایش بدید.
خب تا اینجا ما عملیات ایجاد رکورد جدید رو کامل کردیم، اما برای تغییر رکورد جاری (Update).
ما میخواهیم وقتی کاربر روی یک رکورد در DataGridView دابل کلیک کرد، frmStudent باز بشه و مقادیر رکورد انتخاب شده در کنترلهای مربوطه نمایش داده بشه، برای این کار در داخل رویداد CellDoubleClick مربوط به DataGridViewمون، این کد رو مینویسیم :
:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// create new DsTestDb.StudentRow from focused row
DsTestDb.StudentRow currentRow = this.dt.Rows[e.RowIndex] as DsTestDb.StudentRow;
// save our object to our Application Domain
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", currentRow);
// create new object from frmStudent and pass true to it's constructor (it is edit mode)
frmStudent frm = new frmStudent(true);
if (frm.ShowDialog() == DialogResult.OK)
{
}
}
خب، به فرم frmStudent میریم، تا در رویداد Load آن، آبجکت ذخیره شده در AppDomain رو بگیریم و مقادیرش رو در کنترلهای مربوطه نمایش بدیم، اما ما فقط میخواهیم این کار در زمان Edit انجام بشه، پس ابتدا شرط Edit بودن فرم رو بررسی میکنیم، و بعد کدمون رو مینویسیم :
private void frmStudent_Load(object sender, EventArgs e)
{
if (this.isEditMode)
{
// create object from AppDomain class to retrieve our currentRow object that saved to it via Form1
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
// note, we must cast it to our class
DsTestDb.StudentRow currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
this.txtFirstName.Text = currentRow.fName;
this.txtLastName.Text = currentRow.lName;
}
}
حالا، باید دکمه ی OK رو برای حالت Edit عملیاتی کنیم، این کار رو قبلا برای حالت Insert انجام دادیم، به خاطر همین، برای اینکه کدهای مربوط به Insert و Update، هرکدام در حالتهای خودش اجرا بشن، کد رویداد btnOK_Click رو به این شکل تغییر میدهیم که ابتدا مقدار متغیر isEditMode رو بررسی میکنیم که اگر true بود، کدهای مربوط به Update اجرا شوند، کدهای مربوط به Insert هم در بخش else قرار خواهند گرفت :
:
private void btnOK_Click(object sender, EventArgs e)
{
if (this.isEditMode)
{
}
else
{
// create new student object from student class and set properties
Student st = new Student();
st.FName = this.txtFirstName.Text;
st.LName = this.txtLastName.Text;
// save our object to our Application Domain
// by this technique, we can transfer values between all forms
// note, the name of the object that we want to access to it via other forms is 'Student'
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", st);
// this line, pass DialogResult.OK to our form and then close it
this.DialogResult = DialogResult.OK;
}
}
اکنون، کد مربوط به قسمت Update رو در بلوک if، به صورت زیر مینویسیم :
:
// create object from AppDomain class to retrieve our currentRow object that saved to it via Form1
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
DsTestDb.StudentRow currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
// change it's property values to new values
currentRow.fName = this.txtFirstName.Text;
currentRow.lName = this.txtLastName.Text;
// then, save again it to currentDomain
currentDomain.SetData("Student", currentRow);
// close form and return DialogResult.OK to caller
this.DialogResult = DialogResult.OK;
نتیجه باید به شکل زیر باشد :
:
private void btnOK_Click(object sender, EventArgs e)
{
if (this.isEditMode)
{
// create object from AppDomain class to retrieve our currentRow object that saved to it via Form1
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
DsTestDb.StudentRow currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
// change it's property values to new values
currentRow.fName = this.txtFirstName.Text;
currentRow.lName = this.txtLastName.Text;
// then, save again it to currentDomain
currentDomain.SetData("Student", currentRow);
// close form and return DialogResult.OK to caller
this.DialogResult = DialogResult.OK;
}
else
{
// create new student object from student class and set properties
Student st = new Student();
st.FName = this.txtFirstName.Text;
st.LName = this.txtLastName.Text;
// save our object to our Application Domain
// by this technique, we can transfer values between all forms
// note, the name of the object that we want to access to it via other forms is 'Student'
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", st);
// this line, pass DialogResult.OK to our form and then close it
this.DialogResult = DialogResult.OK;
}
}
اکنون به رویداد dataGridView1_CellDoubleClick در Form1 برمیگردیم و کد داخل بلوک if را به صورت زیر مینویسیم :
:
// get Updated data from AppDomain class and pass it our currentRow object
currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
this.adapter.Update(this.dt);
به این صورت، مقدار به روز شده ی آبجکت currentRow رو از AppDomain میگیریم و سپس، متد TableAdapter.Update() رو فراخوانی میکنیم، تا تغییرات به دیتابیس منعکس شود.
حالا کد رویداد dataGridView1_CellDoubleClick باید به صورت زیر باشه :
:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// create new DsTestDb.StudentRow from focused row
DsTestDb.StudentRow currentRow = this.dt.Rows[e.RowIndex] as DsTestDb.StudentRow;
// save our object to our Application Domain
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", currentRow);
// create new object from frmStudent and pass true to it's constructor (it is edit mode)
frmStudent frm = new frmStudent(true);
if (frm.ShowDialog() == DialogResult.OK)
{
// get Updated data from AppDomain class and pass it our currentRow object
currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
this.adapter.Update(this.dt);
}
}
خب، تا اینجای کار عملیات Insert و Update رو به وسیله ی TableAdapter و Stored Procedures به صورت کاملا Strongly-Typed انجام دادیم، برای عملیات Delete هم میتونید یک Button به Form1 اضافه کنید، تا کاربر پس از انتخاب رکورد مورد نظر و کلیک بر روی دکمه ی Delete، رکورد مورد نظر رو Delete کنید، مثل کد زیر :
:
private void btnDelStudent_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure want to delete this item ?", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
// create new StudentRow from focused row
DsTestDb.StudentRow currentRow = this.dt.Rows[this.dataGridView1.CurrentRow.Index] as DsTestDb.StudentRow;
currentRow.Delete();
this.adapter.Update(this.dt);
}
}
خب، اینم از عملیات CRUD به وسیله ی Data Access Layer ای که Vs2005 برای ما Generate کرد.
اما هنوز کار ما با TableAdapter و Data Access Layer تموم نشده و ما میخواهیم از Stored Procedure های بیشتری (جدا از Spهای عملیاتی CRUD) توی برنامه مون استفاده کنیم.
ما میخواهیم یک TextBox و یک Button روی فرم بکشیم و بر اساس id مورد نظر، رکورد رو از جدول Student، Select کنیم.
پس از کشیدن یک TextBox و یک Button روی Form1، به DataSet Designer بروید و روی StudentTableAdapter راست کلیک کنید و Add Query رو بزنید.
http://pnu-club.com/imported/2009/10/9.jpg
در Wizard ظاهر شده، گزینه ی Use Existing Stored Procedures رو انتخاب و روی Next کلیک کنید.
sp_Student_SelectRow را از لیست کشویی انتخاب کنید(به پارامتری که میگیره و همچنین فیلدهایی که برمیگردونه هم دقت کنید).
گزینه ی Tabular Data رو تیک بزنید و روی Next کلیک کنید.
برای دو متد مشخص شده، نامهای مناسبی انتخاب کنید(من از نامهای FillStudentById و GetStudentById استفاده کردم) و رویNext کلیک نمایید و سپس روی Finish کلیک کنید.
(می بینید که دو متد دیگر به قسمت StudentTableAdapter اضافه شد)
اکنون در رویداد کلیک Button جدیدی که ساختیم، کد زیر رو مینویسیم و مقدار Id رو هم از TextBox ساخته شده میگیریم :
private void btnSearchByID_Click(object sender, EventArgs e)
{
this.adapter.FillStudentById(this.dt, int.Parse(this.txtID.Text));
}
خب، اینم از اضافه کردن یک Query، جدای از Queryهای مربوط به CRUD،به TableAdapter مون، خب، بعد از یک جستجو، ما ممکنه دوباره بخواهیم کل اطلاعاتمون رو از جدول Student بخونیم، پس دوباره یک Button به فرممون اضافه میکنیم، اما این بار دیگه نمی خواهیم از TableAdapter.Fill() یا TableAdapter.GetData() استفاده کنیم، ما میخواهیم رکوردهامون رو با سرعت بیشتری از دیتابیس بخونیم، به عبارتی ما میخواهیم TableAdapter مون رو طوری سفارشی کنیم که علاوه بر متدهای فوق، متد دیگری داشته باشد که به ما SqlDataReader برگرداند، برای این منظور، مراحل زیر رو دنبال میکنیم :
- یک کلاس جدید همنام TableAdapter تون (در اینجا StudentTableAdapter) اضافه کنید.
- در کلاس جدید، فضای نام System.Data.SqlClient رو به سورس کدتون اضافه کنید.
- اگه دقت کرده باشید، کلاس StudentTableAdapter داخل فضای نامی به نام DsTestDbTableAdapters بود، پس فضای نام سورس کدتون رو از DataAccessLayer به DataAccessLayer.DsTestDbTableAdapters تغییر نام دهید، تا دقیقا به همون کلاس اشاره کنید.
خب، در حقیقت ما داریم همان کلاس StudentTableAdapter رو ادامه میدیم، به همین جهت فضای نام و نام کلاس رو دقیقا همنام آن در نظر گرفتیم، نکته ی دیگه ای که باید توجه کنید اینه که با تشکر از قابلیت جدیدی که در C# 2.0 معرفی شد، به نام Partial Class، که اجازه میده کلاستون رو در چند سورس کد مجزا تعریف کنید کنید، پس ما هم کلاسمون رو به صورت public partial تغییر میدیم و سپس متدی با نام GetStudentAsReader تعریف میکنیم که این متد، آبجکتی از نوع SqlDataReader برمیگردونه، مثل کد زیر :
namespace DataAccessLayer.DsTestDbTableAdapters
{
public partial class StudentTableAdapter
{
public SqlDataReader GetStudentAsReader()
{
this.Adapter.SelectCommand = this.CommandCollection[0];
this.Connection.Open();
return this.Adapter.SelectCommand.ExecuteReader(System.Da ta.CommandBehavior.CloseConnection);
}
}
}
یک نکته ی دیگه هم دقت کنید، که چون کلاس ما، ادامه ی کلاس StudentTableAdapter است (نه کلاس مشتق شده از آن)، پس ما به تمام متغیرهای خصوصی و عمومی اون کلاس دسترسی داریم، پس در اینجا میتونیم به راحتی از آبجکت Adapter استفاده کنیم.
خب اینم از سفارشی سازی کلاس StudentTableAdapter، حالا باید در رویداد کلیک Button جدیدمون، کد زیر رو بنویسیم :
:
private void btnLoadAll_Click(object sender, EventArgs e)
{
if (this.dt.Rows.Count > 0)
this.dt.Clear();
this.dt.Load(this.adapter.GetStudentAsReader());
}
به این صورت، اطلاعات رو به صورت آبجکتی از نوع SqlDataReader از StudentTableAdapter میگیریم و در آبجکت dt مون بارگذاری میکنیم.
خب، اینم از ایجاد لایه ی Data Access به کمک Visual Studio 2005 DataSet Designer که برای شما هزاران خط کد رو به صورت اتوماتیک Generate میکنه. امیدوارم این مقاله مورد توجه شما دوستان قرار گرفته باشه، هرگونه کم و کاستی هم به بزرگی خودتون ببخشید. منتظر نظرات شما عزیزان هستم.
بسیاری از ما ممکنه اسم DataSet Disgner به گوشمان خورده باشد، و یا حتی به کرات از آن در برنامه های خود استفاده کرده باشیم، ولی در مورد اینکه این ابزار چقدر میتونه ما رو در روند تولید نرم افزارهای دیتابیس کمک کنه شاید برای ما دور از تصور باشه، در این مقاله قصد بکارگیری این ابزار قدرتمند رو برای ایجاد لایه ی Data Access به شما عزیزان دارم و کاربرد اون رو طی یک پروژه ی عملی به شما نشان خواهم داد، پس بدون مقدمه ی اضافی میریم سر بحث اصلی :
پیش از شروع درس، خدمت شما عرض کنم که دیتابیس نمونه ی ما به نام TestDB میباشد که شامل یک جدول به نام Student و تعدادی رکورد است، همچنین دیتابیس ما شامل 5 Stored Procedure است که در این مقاله از آنها استفاده خواهیم کرد، پروژه ی آماده و اسکریپت T-Sql مربوط به دیتابیس رو میتوانید از انتهای همین مقاله دریافت نمایید.
همچنین، ما برای انتقال مقادیر بین فرمهای مختلف برنامه از کلاسی به نام AppDomain استفاده میکنیم، که از طریق آن، به فضای حافظه ای که برنامه ی ما در حال اجرا در داخل آن است دسترسی پیدا میکنیم، بدین صورت میتوانیم، مقادیر مورد نظر را در محدوده ای امن، در داخل فضای اختصاص داده شده به برنامه ی ما قرار دهیم و از آن در سطح کل برنامه ی خود استفاه نماییم. این کلاس دارای دو متد SetData() و GetData() میباشد که هر کدام به ترتیب برای ذخیره ی مقادیر با یک نام مشخص و گرفتن مقدار از طریق پاس کردن نام آبجکت مورد نظر مورد استفاده قرار میگیرد.
نکته ی دیگه اینکه، من برای پیچیدگی و سردرگمی کمتر، کدنویسی رو به صورت ساده انجام دادم، تا بتونم در هر قسمت از کد نویسی، توضیحات مربوطه رو بیان کنم، مثلا ممکنه در بلوک if یک آبجکت تعریف کرده باشم و در بلوک else آن نیز، همان آبجکت را با مقدار دیگری تعریف کرده باشم، این کار صرفا برای خوانایی و راحتی فهم کد انجام شده تا بتوانم هر قسمت یا بلوک رو به طور مجزا توضیح بدم، لیکن، شما میتوانید کدهای مورد نظر را بهینه نمایید.
ابتدا فایل Sql ای که ضمیمه ی مقاله شده را در Sql Server Management Studio (SSMS) اجرا کنید تا دیتابیس مورد نظر ساخته بشه، سپس شروع به خواندن ادامه ی مقاله کنید :
- پروژه ای جدید از نوع Windows Application به نام DataAccessLayer (یا هر نام دیگه ای که دوست دارید) بسازید.
- از منوی Project گزینه ی Add New Item رو کلیک کنید و یک دیتاست به برنامه اضافه نمایید.
(من نام DsTestDb رو برای دیتاستم اضافه کردم)
http://pnu-club.com/imported/2009/10/1.jpg
- مطمئن باشید که در بخش DataSet Designer هستید، در قسمت Server Explorer، به دیتابیس TestDb کانکت شوید(اگر لازم شد، Connection جدیدی بسازید).
http://pnu-club.com/imported/2009/10/2.jpg
- چون میخواهیم از بالاترین Performance در برنامه هایمان و همچنین اصولی ترین روش در تولید نرم افزارهای دیتابیس استفاده کنیم، لذا Stored Procedure ها گزینه ی مناسبی برای فرستادن فرامین T-Sql به دیتابیس است، پس در Serevr Explorer، گره Stored Procedures را Expand کنید، به صورت نمونه چند Sp برای اعمال Insert و Update و Delete ساخته شده که البته موارد دیگه هم در جای خودش بررسی میشه، sp_Student_SelectAll رو با ماوس به صورت Drag & Drop به داخل DataSet Desginer بکشید.
DataSet Designer با توجه نتیجه ی بازگشتی Sp مورد نظر، جدول Student رو برای ما میسازه، اما اگر دقت کنید چون نام جدول Student رو نمیتونه تشخیص بده، نام Sp رو به عنوان جدول Student در نظر میگیره، روی آن Double-Click کنید و به Student تغییر نام دهید.
http://pnu-club.com/imported/2009/10/3.jpg
- در زیر جدول Student، کلاسی به نام StudentTableAdapter ساخته شده، روی آن راست کلیک کنید و Configure رو انتخاب کنید.
http://pnu-club.com/imported/2009/10/4.jpg
- در قسمت Table Adapter Configuration Wizard شما بایستی برای قسمتهای مختلف Insert و Update و Delete، Sp های مربوطه رو انتخاب کنید(برای Select رو قبلا انتخاب کرده بودیم).
توجه : وقتی Sp مربوطه رو انتخاب میکنید، در سمت راست، حتما مطمئن شوید که پارامترهای آن به درستی به Source Column، Map شده باشند، در غیر اینصورت، Column صحیح رو انتخاب کنید.
http://pnu-club.com/imported/2009/10/5.jpg
- روی Next کلیک کنید و نامهای مناسبی برای متدهای مربوطه انتخاب کنید (فعلا با این قسمت کاری نداریم). Next کنید و سپس روی Finish کلیک نمایید.
اکنون TableAdapter ما از طریق Sp هایی که در دیتابیس تعریف کردیم، عملیات CRUD رو انجام میده.
پروژه تون رو Save کنید (مخصوصا صفحه ی DataSet Designer که فعال است)، با این کار Visual Studio تعداد خیلی زیادی کد رو در فایل DataSetName.Designer.cs ایجاد خواهد کرد و هر بار که تغییری در DataSet میدید، پس از ذخیره ی فایل مورد نظر، کدهای مربوطه تولید خواهند شد.
بیایید نگاهی به کد تولید شده در DataSetName.Designer.cs (و در اینجا DsTestDb.Designer.cs) بندازیم :
کلاسی به نام StudentTableAdapter که در NameSpace ای به نام DsTestDbTableAdapters ساخته شده که در دل خودش مجموعه ای از آبجکتهای SqlDataAdapter,SqlCommand,SqlConnection , … رو در برداره و کلیه ی عملیات CRUD بر روی جدول Student توسط آبجکت ساخته شده از این کلاس انجام میشه.
کلاس DsTestDb که خود شامل چند کلاس زیرمجموعه، از جمله StudentDataTable و StudentRow میباشد که StudentRow از کلاسی به نام DataRow مشتق شده که یک رکورد را در خود نگهداری میکند، تفاوت این کلاس با DataRow در این است که شما به صورت کاملا Strongly-Typed با جدول Student کار میکنید و دقیقا انواع فیلدها، همه از انواعی هستند که در دیتابیس تعریف شده اند. کلاس StudentDataTable هم که از کلاس DataTable مشتق شده و در برگیرنده ی مجموعه ای از StudentRow ها میباشد.
کلاس DsTestDb هم که از کلاس DataSet مشتق شده است.
- خب، قبل از اینکه دست به کار بشیم و شروع به نوشتن کدهای CRUD بکنیم، توصیه میکنم، کلاسی به نام Student بسازید که دارای تمام خصیصه های فیلدهای جدول Student باشه، مثل کد زیر :
public class Student
{
private int id;
private string fName;
private string lName;
public Student()
{
// do nothing
}
public int Id
{
get { return id; }
set { id = value; }
}
public string FName
{
get { return fName; }
set { fName = value; }
}
public string LName
{
get { return lName; }
set { lName = value; }
}
}
مورد استفاده این کلاس، برای راحتی کار با داده ها در زمان Insert است.
- خب، یک DataGridView به فرم اضافه کنید و در سورس کد کلاس Form1 دو آبجکت از کلاسهای زیر ایجاد کنید.
http://pnu-club.com/imported/2009/10/6.jpg
- در رویداد Form_Load آبجکت dt رو Fill کنید و DataGridView.DataSource رو بهش Bind کنید :
http://pnu-club.com/imported/2009/10/7.jpg
برنامه رو کامپایل و اجرا کنید تا اطلاعات، نمایش داده بشه. تا اینجا فقط خواندن اطلاعات رو با TableAdapter انجام دادیم و اکثرا هم این کار رو بلد هستید، اما از اینجا به بعد، یعنی عملیات تغییر داده ها رو میخواهیم با بهترین Performance انجام بدیم، خب مثل من یه Button به فرمتون اضافه کنید، میخواهیم وقتی کاربر روی این Button کلیک کرد، فرم Add New Student ظاهر بشه، پس از اضافه کردن یک Button، یک فرم هم به برنامه تون اضافه کنید با نام frmStudent و به شکل زیر طراحی کنید :
http://pnu-club.com/imported/2009/10/8.jpg
ما در دو نوبت با فرم جدیدمون (frmStudent) کار داریم، یکی زمان Insert و دیگری زمان Update، پس برای اینکه مشخص کنیم در هر زمان که به این فرم دسترسی داریم در چه وضعیتی هستیم، کد کلاس frmStudent رو به صورت زیر اصلاح میکنیم :
public partial class frmStudent : Form
{
private bool isEditMode;
public frmStudent(bool editMode)
{
InitializeComponent();
this.isEditMode = editMode;
}
}
اینطوری هر وقت بخواهیم یک آبحکت از کلاس frmStudent بسازیم تا نمایش بدیم، مشخص میکنیم که در چه وضعیتی هستیم، فعلا برای وضعیت Insert میخواهیم کدنویسی کنیم، پس در رویداد دکمه ی OK، این کد رو مینویسیم :
private void btnOK_Click(object sender, EventArgs e)
{
// create new student object from student class and set properties
Student st = new Student();
st.FName = this.txtFirstName.Text;
st.LName = this.txtLastName.Text;
// save our object to our Application Domain
// by this technique, we can transfer values between all forms
// note, the name of the object that we want to access to it via other forms is 'Student'
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", st);
// this line, pass DialogResult.OK to our form and then close it
this.DialogResult = DialogResult.OK;
}
برای دکمه ی Cancel هم میتونیم از کد زیر استفاده کنیم :
:
private void btnCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
}
- خب، حالا به Form1 برمیگردیم تا برای دکمه ی Add New Student کد زیر را بنویسیم :
private void btnAddStudent_Click(object sender, EventArgs e)
{
// create new object from frmStudent and pass false to constructor to indicate we are not in edit mode
frmStudent frm = new frmStudent(false);
if (frm.ShowDialog() == DialogResult.OK)
{
// create object from AppDomain class to retrieve our st object that pass to it via frmStudent
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
// note, we must cast it to our class
Student st = currentDomain.GetData("Student") as Student;
// create strongly-typed row from StudentRow
DsTestDb.StudentRow newRow = this.dt.NewStudentRow();
newRow.fName = st.FName;
newRow.lName = st.LName;
// add our new row to or dt
this.dt.Rows.Add(newRow);
// reflect our changes to database by applying Update command and pass our dataTable to it
this.adapter.Update(this.dt);
}
}
دقت کنید که ما برای راحتی کار از کلاس Student استفاده کردیم، وگرنه میتونستیم پس از تعریف آبجکت newRow، اون رو به frmStudent پاس بدیم و پس از بسته شدن frmStudent و برگرداندن مقدار DialogResult.OK، دوباره آبجکت مقدار دهی شده ی newRow رو بگیریم و به dt مون اضافه کنیم، اینجوری دیگه نیاز به کلاس Student نخواهیم داشت(انتخاب با خودتونه).
نکته ی دیگه اینکه در frmStudent، چون فیلد id در جدول Student در دیتابیس، به صورت identity هست، ما به اون مقدار ندادیم.
نکته ی مهم دیگه اینکه، من از DataRow برای ایجاد رکورد جدید استفاده کردم تا بتونم رکورد جدید رو مستقیما به آبجکت dt اضافه کنم، سپس، از متد TableAdapter.Update استفاده کردم تا تغییرات ایجاد شده در dt رو capture کنه و به دیتابیس منعکس کنه، اینطوری، بعد از اضافه کردن رکورد جدید، دیگه نیازی به Query مجدد از دیتابیس برای گرفتن آخرین اطلاعات نداریم مخصوصا زمانی که تعداد رکوردهای جدول زیاد باشه، و یا نرم افزار، تحت شبکه باشه، این مزیت بیشتر خودشو نشون میده و باعث میشه که بار پردازشی سرور کم بشه و همچنین از تعداد queryهای زیاد و نابجا کم بشه، در غیر اینصورت، شما با متد TableAdapter.Insert هم میتونید عمل Insert رو انجام بدید، ولی بعد از اون، باید به صورت دستی اطلاعات به روز شده رو نمایش بدید.
خب تا اینجا ما عملیات ایجاد رکورد جدید رو کامل کردیم، اما برای تغییر رکورد جاری (Update).
ما میخواهیم وقتی کاربر روی یک رکورد در DataGridView دابل کلیک کرد، frmStudent باز بشه و مقادیر رکورد انتخاب شده در کنترلهای مربوطه نمایش داده بشه، برای این کار در داخل رویداد CellDoubleClick مربوط به DataGridViewمون، این کد رو مینویسیم :
:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// create new DsTestDb.StudentRow from focused row
DsTestDb.StudentRow currentRow = this.dt.Rows[e.RowIndex] as DsTestDb.StudentRow;
// save our object to our Application Domain
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", currentRow);
// create new object from frmStudent and pass true to it's constructor (it is edit mode)
frmStudent frm = new frmStudent(true);
if (frm.ShowDialog() == DialogResult.OK)
{
}
}
خب، به فرم frmStudent میریم، تا در رویداد Load آن، آبجکت ذخیره شده در AppDomain رو بگیریم و مقادیرش رو در کنترلهای مربوطه نمایش بدیم، اما ما فقط میخواهیم این کار در زمان Edit انجام بشه، پس ابتدا شرط Edit بودن فرم رو بررسی میکنیم، و بعد کدمون رو مینویسیم :
private void frmStudent_Load(object sender, EventArgs e)
{
if (this.isEditMode)
{
// create object from AppDomain class to retrieve our currentRow object that saved to it via Form1
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
// note, we must cast it to our class
DsTestDb.StudentRow currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
this.txtFirstName.Text = currentRow.fName;
this.txtLastName.Text = currentRow.lName;
}
}
حالا، باید دکمه ی OK رو برای حالت Edit عملیاتی کنیم، این کار رو قبلا برای حالت Insert انجام دادیم، به خاطر همین، برای اینکه کدهای مربوط به Insert و Update، هرکدام در حالتهای خودش اجرا بشن، کد رویداد btnOK_Click رو به این شکل تغییر میدهیم که ابتدا مقدار متغیر isEditMode رو بررسی میکنیم که اگر true بود، کدهای مربوط به Update اجرا شوند، کدهای مربوط به Insert هم در بخش else قرار خواهند گرفت :
:
private void btnOK_Click(object sender, EventArgs e)
{
if (this.isEditMode)
{
}
else
{
// create new student object from student class and set properties
Student st = new Student();
st.FName = this.txtFirstName.Text;
st.LName = this.txtLastName.Text;
// save our object to our Application Domain
// by this technique, we can transfer values between all forms
// note, the name of the object that we want to access to it via other forms is 'Student'
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", st);
// this line, pass DialogResult.OK to our form and then close it
this.DialogResult = DialogResult.OK;
}
}
اکنون، کد مربوط به قسمت Update رو در بلوک if، به صورت زیر مینویسیم :
:
// create object from AppDomain class to retrieve our currentRow object that saved to it via Form1
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
DsTestDb.StudentRow currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
// change it's property values to new values
currentRow.fName = this.txtFirstName.Text;
currentRow.lName = this.txtLastName.Text;
// then, save again it to currentDomain
currentDomain.SetData("Student", currentRow);
// close form and return DialogResult.OK to caller
this.DialogResult = DialogResult.OK;
نتیجه باید به شکل زیر باشد :
:
private void btnOK_Click(object sender, EventArgs e)
{
if (this.isEditMode)
{
// create object from AppDomain class to retrieve our currentRow object that saved to it via Form1
AppDomain currentDomain = AppDomain.CurrentDomain;
// declare new object from Student class and assign our saved data to it
DsTestDb.StudentRow currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
// change it's property values to new values
currentRow.fName = this.txtFirstName.Text;
currentRow.lName = this.txtLastName.Text;
// then, save again it to currentDomain
currentDomain.SetData("Student", currentRow);
// close form and return DialogResult.OK to caller
this.DialogResult = DialogResult.OK;
}
else
{
// create new student object from student class and set properties
Student st = new Student();
st.FName = this.txtFirstName.Text;
st.LName = this.txtLastName.Text;
// save our object to our Application Domain
// by this technique, we can transfer values between all forms
// note, the name of the object that we want to access to it via other forms is 'Student'
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", st);
// this line, pass DialogResult.OK to our form and then close it
this.DialogResult = DialogResult.OK;
}
}
اکنون به رویداد dataGridView1_CellDoubleClick در Form1 برمیگردیم و کد داخل بلوک if را به صورت زیر مینویسیم :
:
// get Updated data from AppDomain class and pass it our currentRow object
currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
this.adapter.Update(this.dt);
به این صورت، مقدار به روز شده ی آبجکت currentRow رو از AppDomain میگیریم و سپس، متد TableAdapter.Update() رو فراخوانی میکنیم، تا تغییرات به دیتابیس منعکس شود.
حالا کد رویداد dataGridView1_CellDoubleClick باید به صورت زیر باشه :
:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// create new DsTestDb.StudentRow from focused row
DsTestDb.StudentRow currentRow = this.dt.Rows[e.RowIndex] as DsTestDb.StudentRow;
// save our object to our Application Domain
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("Student", currentRow);
// create new object from frmStudent and pass true to it's constructor (it is edit mode)
frmStudent frm = new frmStudent(true);
if (frm.ShowDialog() == DialogResult.OK)
{
// get Updated data from AppDomain class and pass it our currentRow object
currentRow = currentDomain.GetData("Student") as DsTestDb.StudentRow;
this.adapter.Update(this.dt);
}
}
خب، تا اینجای کار عملیات Insert و Update رو به وسیله ی TableAdapter و Stored Procedures به صورت کاملا Strongly-Typed انجام دادیم، برای عملیات Delete هم میتونید یک Button به Form1 اضافه کنید، تا کاربر پس از انتخاب رکورد مورد نظر و کلیک بر روی دکمه ی Delete، رکورد مورد نظر رو Delete کنید، مثل کد زیر :
:
private void btnDelStudent_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure want to delete this item ?", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
// create new StudentRow from focused row
DsTestDb.StudentRow currentRow = this.dt.Rows[this.dataGridView1.CurrentRow.Index] as DsTestDb.StudentRow;
currentRow.Delete();
this.adapter.Update(this.dt);
}
}
خب، اینم از عملیات CRUD به وسیله ی Data Access Layer ای که Vs2005 برای ما Generate کرد.
اما هنوز کار ما با TableAdapter و Data Access Layer تموم نشده و ما میخواهیم از Stored Procedure های بیشتری (جدا از Spهای عملیاتی CRUD) توی برنامه مون استفاده کنیم.
ما میخواهیم یک TextBox و یک Button روی فرم بکشیم و بر اساس id مورد نظر، رکورد رو از جدول Student، Select کنیم.
پس از کشیدن یک TextBox و یک Button روی Form1، به DataSet Designer بروید و روی StudentTableAdapter راست کلیک کنید و Add Query رو بزنید.
http://pnu-club.com/imported/2009/10/9.jpg
در Wizard ظاهر شده، گزینه ی Use Existing Stored Procedures رو انتخاب و روی Next کلیک کنید.
sp_Student_SelectRow را از لیست کشویی انتخاب کنید(به پارامتری که میگیره و همچنین فیلدهایی که برمیگردونه هم دقت کنید).
گزینه ی Tabular Data رو تیک بزنید و روی Next کلیک کنید.
برای دو متد مشخص شده، نامهای مناسبی انتخاب کنید(من از نامهای FillStudentById و GetStudentById استفاده کردم) و رویNext کلیک نمایید و سپس روی Finish کلیک کنید.
(می بینید که دو متد دیگر به قسمت StudentTableAdapter اضافه شد)
اکنون در رویداد کلیک Button جدیدی که ساختیم، کد زیر رو مینویسیم و مقدار Id رو هم از TextBox ساخته شده میگیریم :
private void btnSearchByID_Click(object sender, EventArgs e)
{
this.adapter.FillStudentById(this.dt, int.Parse(this.txtID.Text));
}
خب، اینم از اضافه کردن یک Query، جدای از Queryهای مربوط به CRUD،به TableAdapter مون، خب، بعد از یک جستجو، ما ممکنه دوباره بخواهیم کل اطلاعاتمون رو از جدول Student بخونیم، پس دوباره یک Button به فرممون اضافه میکنیم، اما این بار دیگه نمی خواهیم از TableAdapter.Fill() یا TableAdapter.GetData() استفاده کنیم، ما میخواهیم رکوردهامون رو با سرعت بیشتری از دیتابیس بخونیم، به عبارتی ما میخواهیم TableAdapter مون رو طوری سفارشی کنیم که علاوه بر متدهای فوق، متد دیگری داشته باشد که به ما SqlDataReader برگرداند، برای این منظور، مراحل زیر رو دنبال میکنیم :
- یک کلاس جدید همنام TableAdapter تون (در اینجا StudentTableAdapter) اضافه کنید.
- در کلاس جدید، فضای نام System.Data.SqlClient رو به سورس کدتون اضافه کنید.
- اگه دقت کرده باشید، کلاس StudentTableAdapter داخل فضای نامی به نام DsTestDbTableAdapters بود، پس فضای نام سورس کدتون رو از DataAccessLayer به DataAccessLayer.DsTestDbTableAdapters تغییر نام دهید، تا دقیقا به همون کلاس اشاره کنید.
خب، در حقیقت ما داریم همان کلاس StudentTableAdapter رو ادامه میدیم، به همین جهت فضای نام و نام کلاس رو دقیقا همنام آن در نظر گرفتیم، نکته ی دیگه ای که باید توجه کنید اینه که با تشکر از قابلیت جدیدی که در C# 2.0 معرفی شد، به نام Partial Class، که اجازه میده کلاستون رو در چند سورس کد مجزا تعریف کنید کنید، پس ما هم کلاسمون رو به صورت public partial تغییر میدیم و سپس متدی با نام GetStudentAsReader تعریف میکنیم که این متد، آبجکتی از نوع SqlDataReader برمیگردونه، مثل کد زیر :
namespace DataAccessLayer.DsTestDbTableAdapters
{
public partial class StudentTableAdapter
{
public SqlDataReader GetStudentAsReader()
{
this.Adapter.SelectCommand = this.CommandCollection[0];
this.Connection.Open();
return this.Adapter.SelectCommand.ExecuteReader(System.Da ta.CommandBehavior.CloseConnection);
}
}
}
یک نکته ی دیگه هم دقت کنید، که چون کلاس ما، ادامه ی کلاس StudentTableAdapter است (نه کلاس مشتق شده از آن)، پس ما به تمام متغیرهای خصوصی و عمومی اون کلاس دسترسی داریم، پس در اینجا میتونیم به راحتی از آبجکت Adapter استفاده کنیم.
خب اینم از سفارشی سازی کلاس StudentTableAdapter، حالا باید در رویداد کلیک Button جدیدمون، کد زیر رو بنویسیم :
:
private void btnLoadAll_Click(object sender, EventArgs e)
{
if (this.dt.Rows.Count > 0)
this.dt.Clear();
this.dt.Load(this.adapter.GetStudentAsReader());
}
به این صورت، اطلاعات رو به صورت آبجکتی از نوع SqlDataReader از StudentTableAdapter میگیریم و در آبجکت dt مون بارگذاری میکنیم.
خب، اینم از ایجاد لایه ی Data Access به کمک Visual Studio 2005 DataSet Designer که برای شما هزاران خط کد رو به صورت اتوماتیک Generate میکنه. امیدوارم این مقاله مورد توجه شما دوستان قرار گرفته باشه، هرگونه کم و کاستی هم به بزرگی خودتون ببخشید. منتظر نظرات شما عزیزان هستم.