# برنامه نویسی با محصولات مایکروسافت > برنامه نویسی مبتنی بر Microsoft .Net Framework > مقالات مرتبط با Microsoft .Net Framework > مقاله: Creating Data Access Layer via VS2005 DataSet Designer

## hdv212

با توجه به اینکه بسیاری از امکانات 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 رو برای دیتاستم اضافه کردم)


-	مطمئن باشید که در بخش DataSet Designer هستید، در قسمت Server Explorer، به دیتابیس TestDb کانکت شوید(اگر لازم شد، Connection جدیدی بسازید).


-	چون میخواهیم از بالاترین 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 تغییر نام دهید.


-	در زیر جدول Student، کلاسی به نام StudentTableAdapter ساخته شده، روی آن راست کلیک کنید و Configure رو انتخاب کنید.


-	در قسمت Table Adapter Configuration Wizard شما بایستی برای قسمتهای مختلف Insert و Update و Delete، Sp های مربوطه رو انتخاب کنید(برای Select رو قبلا انتخاب کرده بودیم).
توجه : وقتی Sp مربوطه رو انتخاب میکنید، در سمت راست، حتما مطمئن شوید که پارامترهای آن به درستی به Source Column، Map شده باشند، در غیر اینصورت، Column صحیح رو انتخاب کنید.


-	روی 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 دو آبجکت از کلاسهای زیر ایجاد کنید.




-	در رویداد Form_Load آبجکت dt رو Fill کنید و DataGridView.DataSource رو بهش Bind کنید :


برنامه رو کامپایل و اجرا کنید تا اطلاعات، نمایش داده بشه. تا اینجا فقط خواندن اطلاعات رو با TableAdapter انجام دادیم و اکثرا هم این کار رو بلد هستید، اما از اینجا به بعد، یعنی عملیات تغییر داده ها رو میخواهیم با بهترین Performance انجام بدیم، خب مثل من یه Button به فرمتون اضافه کنید، میخواهیم وقتی کاربر روی این  Button کلیک کرد، فرم Add New Student ظاهر بشه، پس از اضافه کردن یک Button، یک فرم هم به برنامه تون اضافه کنید با نام frmStudent و به شکل زیر طراحی کنید :


ما در دو نوبت با فرم جدیدمون (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 رو بزنید.


در 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 میکنه. امیدوارم این مقاله مورد توجه شما دوستان قرار گرفته باشه، هرگونه کم و کاستی هم به بزرگی خودتون ببخشید. منتظر نظرات شما عزیزان هستم.
موفق باشید - حامد وزیری

----------


## Mahdi-563

چون ديدم فقط يه تشكر خشك و خالي كافي نيست گفتم يه تشكر درست و حسابي بكنم از مديران محترم  سايت معضرت ميخوام.

تو اين زمينه خيلي مطالعه كردم ولي چيزي به اين كاملي دستم نيمد.
دوست عزيز خيلي كارت درسته اي والا 1000000000000 به توان 1000000000000 ازت متشكرم.

----------


## hdv212

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

----------


## hanieh66

سلام، خیلی جالب و مفید بود. نمی دونم توی همین تاپیک می شه بحث کرد یا می خواین اینجا رو جمع و جور نگهش دارین!
در هر صورت سوالی داشتم :

من روی یک پروژه که از اکسس استفاده می کنه دارم کار می کنم و تحت شبکه هم هست و مثل همیشه پارامتر سرعت خیلی خیلی مهمه. شما گفتین که fill کردن یک دیتاتیبل زمانگیرتره (درواقع گفتین که اگه بصورت دیتاریدر کار کنیم بهتره. درسته؟) و بهتره از روش دیتا ریدر استفاده کنیم. من این موضوع رو دقیق نمی دونستم. می شه همینجا و یا پست جداگانه ای این موضوع رو توضیح بیشتری بدین؟؟؟
و اینکه چرا ؟؟ و دلیلش چیه که سرعت دیتاریدر بیشتره؟؟؟ و اگه می شه یه نمونه کوچک رو هم پیاده سازیش رو توضیح بدین. 

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

----------


## bachebahal_1363

آقا در برنامه تحت شبکه به چه صورت connectionstring رو تغییر بدم؟

----------


## hdv212

> من روی یک پروژه که از اکسس استفاده می کنه دارم کار می کنم و تحت شبکه هم هست و مثل همیشه پارامتر سرعت خیلی خیلی مهمه. شما گفتین که fill کردن یک دیتاتیبل زمانگیرتره (درواقع گفتین که اگه بصورت دیتاریدر کار کنیم بهتره. درسته؟) و بهتره از روش دیتا ریدر استفاده کنیم. من این موضوع رو دقیق نمی دونستم. می شه همینجا و یا پست جداگانه ای این موضوع رو توضیح بیشتری بدین؟؟؟
> و اینکه چرا ؟؟ و دلیلش چیه که سرعت دیتاریدر بیشتره؟؟؟ و اگه می شه یه نمونه کوچک رو هم پیاده سازیش رو توضیح بدین.


با سلام خدمت شما دوست گرامی
خدمت شما عرض کنم که DataReader به خاطر ماهیت Forward-Only اون دارای سرعت بیشتری نسبت به DataSet است، دلیل این امر اینه که دیتاریدر تا زمانی که اتصال به دیتابیس برقراره داده ها رو به صورت فقط خواندنی از دیتابیس میگیره بدون اینکه ساختاری از دیتابیس و یا جدول شما ایجاد کنه، در واقع این اطلاعاتی که از دیتابیس میاد، به صورت خام یا Raw هستند، و شما برای دسترسی به رکوردها و فیلدهای جدولی که با دیتاریدر خوانده شده، باید از حلقه ها و Loop استفاده کنید، اما در دیتاست قضیه کاملا فرق میکنه، دیتاست علاوه بر ذخیره ی اطلاعات جداول، اطلاعات ساختاری جداول و یا حتی دیتابیس رو هم در خودش ذخیره میکنه، به خاطر همینه که دارای سرعت پایین تری نسبت به دیتاریدر هست، اما قابلیت هایی داره که دیتاریدر نمیتونه داشته باشه، مثل تغییرات داده در دیتاست.
نمونه برنامه هم که در خود مقاله هست، میتونید اونو مرور کنید.




> آقا در برنامه تحت شبکه به چه صورت connectionstring رو تغییر بدم؟


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

----------


## bachebahal_1363

> دوست عزیز سوالت علاوه بر اینکه به این تاپیک مربوط نمیشه، خیلی گنگه، پیشنهاد میکنم در بخش سی شارپ و به صورت جزئی تر سوالتون رو مطرح کنید.


خوب من این سوال رو اینجا مطرح کردم چون شما از Wizard برای Quary گرفتن و DataSet و DataAdapter استفاده کردین . 
منظور من به صورت دقیق این هست که شما زمانی که یک دیتاست از دیتابیستون در برنامه می سازین دیتاست در زمان ساخت ConnectionString خودش رو در Setting برنامه از Application scop, استفاده می کنه که توسط User قابل تغییر نیست . من می خوام بدونم زمانی که برنامه تحت شبکه می ره برای مثال یک کلاینت به چه صورت می تونه CnnectionString مربوط به سرور رو به دیتاست انتقال بده . 

برای مثال ConnectionString دیتاست زمان ساخت :

Data Source=(local);Initial Catalog=DB;Integrated Security=SSPI;

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

"Data Source=192.168.0.1;Initial Catalog=DB;Integrated Security=SSPI"

خوب سوال من دقیقا این هست که چطورمی شه ConnectionString دیتاست رو برای بدست آوردن اطلاعات از سرور تغییر داد ؟

----------


## mahdi_farhani

کی گفته نمیشه تغییر داد . اگر WEBApp باشه از webconfig قابل تغییر هست .
و اگر Win app باشه از تو app.config میتونی تغییر بدی

----------


## bachebahal_1363

> کی گفته نمیشه تغییر داد . اگر WEBApp باشه از webconfig قابل تغییر هست .
> و اگر Win app باشه از تو app.config میتونی تغییر بدی


چطور می شه در setting و یا همون app.config متغییر هایی که با دید Application هستند رو تغییر داد می شه شما با یه برنامه این کار رو به ما نشون بدین .
دیتاست از connectionString که در Setting برنامه هست و به صورت Application هست استفاده می کنه . چطور می شه اون رو تغییر داد ؟

----------


## hdv212

> چطور می شه در setting و یا همون app.config متغییر هایی که با دید Application هستند رو تغییر داد می شه شما با یه برنامه این کار رو به ما نشون بدین .
> دیتاست از connectionString که در Setting برنامه هست و به صورت Application هست استفاده می کنه . چطور می شه اون رو تغییر داد ؟


منظور دوستمون در پست شماره 8 اینه که شما خودت میتونی به صورت دستی، فایل app.config رو تغییر بدی، علاوه بر این، میتونی خاصیت ConnectionString مربوط به TableAdapter رو هم از طریق کد تغییر بدی

----------


## smaj2007

دوست عزیز  hdv212
مطلب Creating Data Access Layer از طریق  dataset  بسیار جالب بود . البته این مورد رو من از سری مقالات سایت asp.net  مطالعه کرده بودم . فقط یک مشکلی در مورد تولید کد لایه business 
دارم که تو اون سایت مطلب خیلی سنگین توضیح داده (البته اینم بگم که تو زمینه دانت نت من هنوز خیلی مسلط نیستم) . خواهشی که ازتون دارم اینه که اگه ممکنه در این مورد یک مقاله ساده و روان توضیح بدین در مورد تولید کد این لایه که بصورت ویژوال است یا دسته و کلا به چه صورت میشه عمل کرد .

----------


## hdv212

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


Bussiness Layer لایه ای است شامل کلاسهای دات نت که هر کدام برای یک آبجکت در دیتابیس ساخته میشود (که معمولا این آبجکتها جداول هستند)، و شما برای راحتی کار با داده های جداول (که معمولا به صورت مستقیم با دیتابیس ارتباط برقرار میکردید) با این لایه کار خواهید کرد.




> در مورد تولید کد این لایه که بصورت ویژوال است یا دسته و کلا به چه صورت میشه عمل کرد


منظورتون در این مورد چیه ؟

----------


## dehghanimeh

دوست عزیز سلام
واقعا عالی بود . میتونم بگم یه جورایی دید من رو به برنامه های بانک اطلاعاتی 
عوض کرد.
اگر بتونید آموزش همراه به مثال Presentation Layer Business Logic Layer
و یه مثال که شامل هر سه لایه باشه  :متعجب: 

این  برنامه که پایینه لایه ها رو تولید میکنه میشه یه کمی در مورد کدهاش توضیح بدین

آیا بهینه است؟
کدوم لایه رو تولید میکنه؟
چطور باید استفاده بشه؟

https://barnamenevis.org/attach...3&d=1221721683

----------


## user22

سلام آقای وزیری
باتشکر از مقاله بسیار عالیتون که حداقل واسه من خیلی مفید بود 
من یه سوال داشتم (البته در موردASP.NET  )
من می خوام با کلیک روی دکمه ، صفحه جدید در یک پنجره جدید(browser) باز بشه 
(و بعد در پنجره جدید ، با زدن یک دکمه دیگه ،  پنجره بسته بشه)
البته من میخوام به اون پنجره جدیده مقادیری هم ارسال کنم 
آیا دستور Response.Redirect(targetURL
قابلیت بازکردن در پنجره جدید را میده یا اینکه دستور دیگه ای لازمه ؟
اگه میشه ایمیلتون رو بهم بدید (در صورت امکان جوابو به ایمیلم بفرستید :لبخند: )
من حداکثر 2-3 روزه جوابو میخوام . خیلی خیلی ممنون
seif1384@yahoo.com

----------


## sahele_sheni

با سلام به همهٔ دوستان . به یه موردی برخورد کردم که نتیجه واسم جالب بود . می‌خوام اینجا بذارم تا اگه بقیهٔ دوستان هم خواستن استفاده کنن . 
من توی جدول یه فیلد دارم از نوع بیت . حالا وقتی‌ که این جدول رو به یه گرید بایند می‌کنم چیزی که توی اون گرید به ازای‌ این فیلد  نشون داده می‌شه به این صورت‌ دیده می‌شه 
 

همانطور که می‌بینید برای فیلد زمین یک checkbox قرار میگیره . ولی‌ می‌خوایم به جای این checkbox یه متن اونجا داشته باشیم . به سراغ dataset میریم و اون table که می‌خوایم این کار روش انجام بشه . روی اون table راست کلیک می‌کنیم و یک column جدید به اون جدول اضافه می‌کنیم . در اینجا من اسمشو میزارم "zamincolumn".
روی این فیلد اضافه شده کلیک می‌کنیم و properties میگیریم . توی پنجره properties یه خاصیت هست به اسم "expression".حالا با مقدار دهی‌ به این property میتوانیم مقدار این فیلد جدید رو با توجه به مقدار فیلد "زمین" تعیین کنیم . 
 
توی این property همانطور که توی تصویر هم مشخص این عبارت شرطی قرار میگیره . 

iif((zamin=0),'دارد','ندارد')

و حالا نتیجه ای که از bind کردن این جدول جدید به گرید به دست میاد به این صورت‌ خواهد بود . 
 

حالا دیگه شما میتونید اون فیلد  از نوع checkbox رو از توی گرید خارج کنید . 

در مورد expression میتونید توضیحات کاملتر رو از اینجا بخونید . 

موفق باشید

----------


## hosseinab

با سلام و تشکر از hdv212 عزیز
می خواستم بگم تصاویر مقاله برای من نمایش داده نمی شود اگر می شود رسیدگی می کنید.
ممنون

----------

