نمایش نتایج 1 تا 25 از 25

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

  1. #1
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    برنامه نویسی پایگاه داده به صورت گام به گام

    فهرست مطالب : همین صفحه پست دوم

    توجه:

    فعلا تاپیک در حال ایجاد است لطفا تا تکمیل مراحل اولیه ایجاد تاپیک از ارسال هرگونه پستی خودداری نمایید




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


    در ضمن چون ممکن است به دلیل مشغله یا هر دلیل دیگری کامل شدن تاپیک طولانی شود از دوستان خواهشمندم از هرگونه بحث انحرافی و متلک پرانی خوداری کنند

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






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

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

    تصمیم بر آن است در هر مرحله پروژه نمونه طبق توضیحات داده شده تکمیل و جهت دانلود گذاشته شود



    نکته:

    ابزار طراحی مورد استفاده:

    Visual Studio 2010
    Dot Net FramWork 3.5--جهت توانایی تبدیل به VS 2008
    SQL Server 2005 (جهت قابلیت اجرا در VS2008و در نظر گرفتن همه دوستان)
    در صورت داشتن امکانات و توانایی اگر اقدام به طراحی گزارش شود از Crystal Report 2010 استفاده خوهد شد

    در صورت هرگونه تغییر ابزار ، در همین قسمت به اطلاع خواهد رسید


    هینجا هم جا دارد از دوست خوبم ali190 بدلیل کمک های شایان در پیشبرد اهداف تاپیک از صمیم قلب از تشکر کنم


    ضمیمه اصلاح شد 18/01/91 ساعت 20:00 اعمال تغییرات تا پست شماره 21
    فایل های ضمیمه فایل های ضمیمه
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 25 آبان 1391 در 11:55 صبح

  2. #2
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189
    آخرین ویرایش به وسیله فرید نجفلو : جمعه 18 فروردین 1391 در 20:02 عصر

  3. #3
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

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

    ali190
    آخرین ویرایش به وسیله فرید نجفلو : دوشنبه 07 فروردین 1391 در 12:51 عصر

  4. #4
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    پرسش و پاسخ:
    (پرسش هایی که از طریق پیغام خصوصی دریافت می شوند در صورت نیاز در این قسمت مطرح و پاسخ داده خواهند شد)

    ali190:من پروژه رو دانلود کردم ،اسکریپت دیتابیس رو هم اجرا کردم ، منتها روابط میان جداول رو در بخش دیاگرام نمیبینم!
    شما باید در SSMS یک دیاگرام جدید ایجاد و از پنجره Add Table کلیه جدول ها را اضافه کنید تا روابط موجود نمایش داده شود
    آخرین ویرایش به وسیله فرید نجفلو : سه شنبه 08 فروردین 1391 در 23:54 عصر

  5. #5

  6. #6
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    اخبار و اطلاعیه ها:

    اولین سورس مثال عملی در تاریخ 08/01/91 به پست اول اضافه شد!
    آخرین ویرایش به وسیله فرید نجفلو : سه شنبه 08 فروردین 1391 در 19:54 عصر

  7. #7
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    سخن اول:


    هر کسی هر نظر و پیشنهادی میده باتوجه به میزان دانش ، تجربه و ... خودشه و هرکس هر نظری داد کسی حق توهین ، تمسخر و بی ادبی به اون رو نداره(تا این تاپیک هم به سرنوشت بعضی از تاپیک ها که فرهنگ ما رو هم زیر سوال برده نشه!) ولی باید به صورت کاملا مودبانه انتقادات و پیشنهادات گفته بشه تا موجب پیشرفت و دانش آموزی ما بشه


    دوستانی هم که نظر و پیشنهاد می دن سعی کنن اگه در مقوله اشی دانش کافی نداشتن از از اظهار نظر فنی (که ممکنه درست نباشه) خود داری کنن

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

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

    نکته ای درباره روند کار:

    همان طور دوستان می دانند بعد از به وجود آمدن اشیا DataSet و بعد ها (VS2008 و فریم ورک 3.5) با روی کار آمدن تکنولوژی منحصر به فرد LINQ کم کم استفاده از روش های سنتی ADO.NET و TSQL رنگ باخته و رو به منسوخ شدن دارند

    با این حال طبق قرائن و شواهد(سوالات و تاپیک ها) دوستان فعال در سایت و با تعمیم بیشتر ، ما و هم وطنان ارجمند همچنان بر استفاده از TSQL پا فشاری داریم(در واقع ما همیشه سعی داریم چند سالی از پیشرفت و تنکنولوژی ها عقب باشیم!!!)

    به همین دلیل برای جا افتادن تکنولوژی ها روز مطالب ارائه شده با همان روش DataSet انجام شده و در صورتی که امکانات محیا و عمر و توانایی باقی باشد با TSQL و ADO.Net و سپس وقتی TSQL جا افتاد به وسیله LINQ حل خواهد شد
    (پس لطفا درباره اینکه روش های بهتر وجود دارد و... بحث را به انحراف نکشید و بدانید که ما خود به این قضیه واقف هستیم ولی به دلیل مذکور روش ها با اولویت بحث می شوند)

    بعد از اتمام مسائل اصلی پایگاه داده وارد بحث های عمیق تر و پیشرفته تر خواهیم شد از جمله:
    بهینه سازی ، پیشگیری از خطا ها ، حفره های مخوف SQL Injection ، برنامه شبکه ، ایجاد دیتابیس در زمان اجرا (ران تایم) به همراه درصد پیشرفت مربوطه ، کار با چند پایگاه داده (سوئیچ) ، نهان گذاری (Cashing) و ...

    در ضمن مطالب و مثال از SQLServer می باشد چون نمی شود از هر دو نوشت و اینکه تقریبا هرشئی در SqlClient معادلی درOleDb به همان اسم دارد


    در آخر همه دوستان را به رعایت قوانین مکتوب و عرفی سایت و رفتار های انسانی دعوت می کنم
    آخرین ویرایش به وسیله فرید نجفلو : چهارشنبه 12 مهر 1391 در 22:07 عصر

  8. #8
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    طرح مثال عملی:
    مثال زیر رو جهت ادامه مطلب مطرح و طبق آن پایگاه داده خود را طراحی و به تکمیل پروژه خود می پردازیم

    معرفی:
    زمینه فعالیت:
    انبار داری اجناس و کالا ها
    نحوه فعالیت:
    مورد بحث خود موسسه مستقل نبوده و وابسته به بک یا چند موسسه دیگر می باشد که فقط وظیفه دریافت ، نگهداری و تحویل مجدد کالا را بر عهده داشته و همچنین توانایی ارائه آمار کالا را نیز دارد در نتیجه خود مستقیما به خرید و فروش کالا ها نمی پردازد
    پس بخش مربوط به حسابداری و وجوه نقد جدا بوده و در در این بخش هیچگونه وجهی رد وبدل نمی شود

    اجزا موثر بر پروژه:

    *- کالاها:
    کالاها مهمترین جز هستند که هر کدام از آنها نیز به نوبه خود در گروه کالا قرار می گیرند
    اطلاعات هر کالا متشکل شده از : کد کالا ، نام کالا ، گروه کالا ، موجودی فعلی ، حداکثر موجودی قابل انبار
    لازم به ذکر است کالا های مشابه بدون تفاوت در نظر گرفته می شوند یعنی کالای تحول گرفته شده الف از مو سسه 1 با کالای الف موسسه 2 تفوتی نخواهد داشت!

    *- انبارها :
    این بخش دارای تعدای انبار می باشد که کالا را در آنها نگه داری می کند، تعدادی از انبار ها متعلق به خود و و تعدادی نیز استیجاری می باشد. در نتیجه تعداد انبار ها ثابت نبوده و ممکن است طی دوره مالی کم و زیاد شوند هر انبار ظرفیت ذخیره سازی خود را داشته و همچنین هر انباری دارای امکاناتی می باشد که فقط توانایی انبار کردن گروه های خاصی از کالا ها(و نه همه گروه ها) دارا می باشد (برای مثال انباری که دارای سردخانه نباشد گروه کالا های فاسد شدنی را نمی تواند انبار کند)
    اطلاعات انبار ها: کد انبار ،نام انبار،حجم ذخیره سازی ، گروه کالا های قابل انبار ، آدرس ، شماره تلفن
    نکته:حجم انبار را جهت عدم پیچیدگی مثال عددی بدون واحد در نظر خواهیم گرفت یعنی کالای به ندازه 2 متر به اندازه کالایی به به وزن 2 کیلو گرم از ظرفیت انبار خواهد کاست

    *- مشتری ها :
    همان طرف های مقابل می باشند که کالا ها را از آنها دریافت و به آنها تحویل می دهیم
    اطلاعات هر مشتری: کد مشتری،نام مشتری ، زمینه فعالیت ، آدرس دفتر ،شماره تماس مدیریت ، آدرس گارگاه (جهت ارسال کالا) ، شماره تلفن کارگاه

    *- کارکنان:
    موسسه داری چند کارمند می باشد که هر کدام قسمتی از کار را بر عهده دارند و مدیریت نیز سیاست خود را چنین در نظر گرفته کارکنان در بخش های غیر مرتبط به فعالیت نپردازند
    در ضمن ممکن است از مدیران یا مسولان موسسه در نظر داشته باشند از طریق شبکه کامپیوتری موسسه به اطلاعات دستیابی و بر روند اجرا و آمارها نظارت داشته باشند!
    اطلاعات کارکنان: نام کاربری ، کلمه عبور ، نام ، نام خانوادگی، تاریخ ایجاد کاربر، آخرین ورود به سیستم ، مجوز های دسترسی

    *- بخش آماری:
    موجودیت فیزیکی نبوده و به این معنی است که سیستم باید توانایی آمار گیری از کالا ها ، انبار ها و مشتریان را داشته باشد
    از جمله:مقدار کل موجود از هر کالا ، مقدار کل وارد شده مقدار کل صادر شده ، مقدار هر کالا در هر انبار ، مقدار دریافتی هر کلا از هر مشتری ، مقدار فرستاده شده از هر کالا به هر مشتری ، مقدار مجاز قابل ارسال به هر مشتری از هر کالا و...


    با در نظر گرفتن همین مثال و مفروضات به طراحی پایگاه داده خواهیم پرداخت
    آخرین ویرایش به وسیله فرید نجفلو : دوشنبه 07 فروردین 1391 در 20:28 عصر

  9. #9
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ایجاد اشیاء پایگاه داده:


    طبق اطلاعاتی که در اختیار داریم (از مثال مذکور) هدف نهایی ما رسیدن به ترکیبی از اشیائ با اجزا و روابط زیر(تصاویر) خواهد بود(در حالت اکسپلورر گره های غیر مفید حذف شده است):




    همانطور که می بینید نام هر جدول وظیفه خود را توضیح می دهد(نام جداول فارسی نوشته شده است تا قابل فهم تر باشد)
    فقط ممکن است جدول tblDbVer کمی به نظر مبهم بیرسد
    همان طور که در ادامه و در هنگام کد نویسی خواهید دید از طریق این جدول اقدام به شناسایی و اعتبار سنجی پایگاه داده جهت اتصال به آن استفاده خواهد شد!

    جهت ایجاد اشیا (یا در اصل جداول و ارتباطات بین آنها) پایگاه داده ابتدا SSMS(SQL Server Managment Studio) i رو باز کنید (در صورتی ندارید می توانید نسخه Express را برای 2005 و 2008 به صورت رایگان دانلود کنید)

    پس از ظاهر شدن پنجره Connect To Server ، سرور خود را (برای مثال SQLEXPRESS) انتخاب کنید

    ایجاد پایگاه داده جدید:

    از سمت چپ Object Explorer (تصویر دوم بالا) را باز و روی گره Databases کلیک راست و گزینه New Database را انتخاب کنید
    از پنجره باز شده در کادر Database name نام پایگاه داده (WorkWithDb_Sample1) را وارد و دکمه OK را کلیک کنید

    اگر مراحل بالا را درست طی کرده باشید پایگاه داده ما به سرور اضافه و آماده ایجاد جداول هستیم

    ایجاد جداول:

    جهت نمونه دو جدول tblAnbar و tblAnbarKalaGroup را به صورت گام به گام ایجاد می کنیم:

    تحلیل:
    هدف جدول:ذخیره اطلاعات مربوط به انبار ها
    چه اطلاعاتی باید در این جدول ذخیره شوند( تعیین ستون ها یا فیلد ها)
    طبق متن مثال حداقل به فیلد های زیر نیاز داریم


    کد انبار =Code
    نام انبار=Name
    حجم ذخیره سازی =MaxCapacity
    گروه کالا های قابل انبار=KalaGroup
    آدرس=Address
    شماره تلفن=Tell

    همانطور که ملاحظه می شود می توان یک جدول به نام tblAnbar ایجاد و تمام اطلاعات را در آن قرار داد.
    ولی در این میان مشکلی وجود دارد!
    همانطور که از ظواهر هم پیداست یک انبار می تواند بیش از یک گروه از کالا ها را بپذیر!

    اولین راه حل آن است که اطلاعات را در همین جدول ذخیره کنیم و به ازای هر گروه کالا اطلاعات انبار را تکرار و فقط گروه کالای مورد نظر را تغییر داد!

    اما این کار برخلاف اصول طراحی پایگاه داده(اصل نرمال سازی) بوده و همچننین موجب افزونگی اطلاعات خواهد بود!

    راه حل:

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

    در نتیجه هر انبار می تواند فقط یک رکورد در جدول اصلی( tblAnbar ) و هیچ ، یک ، یا چند رکورد در جدول فرزند (tblAnbarKalaGroup ) داشته باشد

    انتخاب کلید اصلی:

    چون کد انبار فقط یک بار می تواند در جدول اصلی ظاهر شود کاندیدای مناسب جهت کلید اصلی می باشد که همین فیلد نیز رابط بین جدول پدر و فرزند خواهد بود

    تعیین کلید اصلی جدول فرزند :

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

    راه حل :

    ما یک فیلد سوم به نام ID از نوع عددی ایجاد و به SQL Server اجازه می دهیم به صورت خودکار در هر ایجاد رکورد جدید مقدار آن را فزایش دهد(خاصیت Identity)

    طبق قانون (SQL Server) این فیلد فقط می تواند افزایش یابد یعنی یک عدد فقط یک بار می تواند یک بار ظاهر شود اگر بزرگترین عدد موجود در این فیلد از جدل 3 باشد مقدار بعدی 4 خواهد بود حتی اگر اعداد 1و2 وجود نداشته باشند
    پس ما همین فیلد را کلید اصلی جدول فرزند قرار می دهیم

    درنتیجه ترکیب جداول به شکل زیر خواهد بود:

    tblAnbar :

    Code
    Name
    MaxCapacity
    Address
    Tell


    tblAnbarKalaGroup :

    ID
    Code
    KalaGroup


    ایجاد جدول tblAnbar :

    از SMSS و Object Explorer سپس گره Databases گر مربوط به WorkWithDb_Sample1 را باز و روی آیکن پوشه با نام Tables کلیک راست و گزینه New Table را انتخاب کنید
    اکنون جدول در حالت طراحی ظاهر می شود
    در زیر ستون Column Name نام فیلد و در Data Type نوع داده و جعبه انتخاب زیر ستون Allow Null نیز نشانگر قبول یا عدم قبول مقدار پوچ (NULL) می باشد

    برای نمونه در سطر اول و ستون اول Code و در ستون دوم Int (همانطور که در تصویر دوم بالا و در زیر گره tblAnbar و مقابل مورد Code و داخل پرانتز قابل مشاهده است) در ستون سوم جعبه انتخاب را خالی کنید(در تصویر NotNull یعنی باید جعبه انتخباب باید خالی شود)
    حالا فیلد های دیگر را طبق تصویر و با این توضیحات ایجاد کنید
    باز همانطور که در تصویر می بینید در کنار نام Code تصویر یک کلید زرد رنگ وجود دارد که مؤید کلید اصلی بودن آن است جهت اعمال این خصوصیت رو سطر مربوط به Code راست کلیک و گزینه Set Primary Key را انتخاب کنید

    کار شما با این جدول تمام شد حالا دکمه Save یا کلید های Ctrl+S را زده و در پنجره ظاهر شده tblAnbar را وارد و تایید کنید تا جدول با همین نام ذخیره شود

    شما با موفقیت یک جدول جدید ایجاد کردید!

    حالا جدول tblAnbarKalaGroup را با توضیحات بالا تا قبل از مرحله ذخیره پیش ببرید
    یک تفاوت عمده این جدول با جدول قبلی در فیلد ID می باشد زیرا این فیلد را باید تنظیم نماییم تا به صورت خود کار افزایش یابد
    نگران نباشید این کار فوق العاده آسان می باشد

    سطر ID را انتخاب و از قسمت زیرین پنجره طراحی(Column Properties) از گره Table Designer و زیر گره Identity Specification مقدار Is Identity را از No به Yes تغییر دهید
    حالا می توانید جدول را با نام tblAnbarKalaGroup ذخیره کنید!

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

    ایجاد رابطه ها:

    همان طور که دید بعضی از جداول با یکدیگر رابطه دارند برای مثال دو جدول tblAnbar و tblAnbarKalaGroup داری رابطه پدر فرزندی و بر اساس کد انبار هستند(زمانی که جدول انبارها را دو تکه کردیم این رابطه ایجاد شد!)

    چرا رابطه ها را ایجاد می کنیم؟

    اولین دلیل و مهمترین آنها حفظ جامعیت داده ها است که یکی از اصول طراحی پایگاه داده می باشد
    یعنی شما فرض کنید انباری ایجاد کرده اید که دو گروه کالا را می تواند قبول کند
    پس ما برای این انبار یک رکورد در جدول tblAnbar و دو رکورد در جدول tblAnbarKalaGroup داریم
    حالا کاربری اقدام به حذف رکورد انبار از جدول tblAnbar می کند اما رکورد های tblAnbarKalaGroup حذف نمی کند
    پس الان ما چه داریم! دو رکورد در tblAnbarKalaGroup که پدری در tblAnbar ندارند(یتیم هستند!)
    این یعنی نقض اصل جامعیت!

    رابطه ایجاد شده چه کاری انجام می دهد؟

    وقتی ما رابطه ای بین دو جدول ایجاد نمودیم DBMS یا سیستم مدیریت پایگاه داده (مخفف DataBase Managment System) که در اینجا همان SQL Server می باشد برطبق رابطه تعریف شده جداول مورد بحث چه در پی عملی عمدی یا سهوی اجازه نخواهد رکورد بدون پدری(یتیم) وجود داشته باشد

    چگونه اطلاعاتی را رابطه دارند حذف کنیم؟

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

    چند نوع رابطه وجود دارد؟

    روابط بین جدول ها در اصول پایگاه داده سه نوع می باشند:

    1:رابطه یک به یک : در این رابطه یک فیلد از جدول باید به یک و فقط یک فیلد از جدول دیگر وابسته باشد(که رابطه است دو طرفه و معمولا بین کلید های اصلی یا ستون های منحصر به فرد برقرار می گردد)

    2:رابطه یک به چند: این همان رابطه ای است که درمثال بالا به آن اشاره و آشنا شدید

    3:رابطه چند به چند: در این رابطه چند فیلد از یک جدول به یک یا جند فیلد از جدول دیگر و بالعکس با هم رابطه دارند
    برای مثال در یک دانشگاه در جدول دانشجویان یک دانشجو می تواند در جدول اساتید یک یا چند استاد داشته باشد و همچنین یک استاد می تواند در جدول دانشجویان یک یا چند دانشجو داشته باشد!
    نکته:رابطه چند به چند در SQL Server پشتیبانی نمی شود!

    چگونه روابط را در SQL Server ایجاد کنید؟

    این کار بسیار راحت می باشد

    از گره های WorkWithDb_Sample1 رو Database Diagrams کلیک راست و گزینه New Database Diagram را انتخاب کنید

    اگر پنجره Add Table ظاهر نشد در جایی خالی از دیاگرام(ناحیه سفید رنگ بزرگ) کلیک راست و گزینه Add Table را انتخاب و جدول های مورد نظر (در این مثال همه جداول) را به دیاگرام اضافه کنید

    برای نمونه جهت ایجاد ارتباط بین دو جدول انبار جدول tblAnbar را که به شکل یک پنجره کوچک است(تصویر اول بالا) انتخاب کنید حالا با موس فیلد Code گرفته کشیده و در جدول tblAnbarKalaGroup روی فیلد Code رها کنید
    در این زمان دو پنجره همزمان باز می شوند

    در پنجره بالایی (Table And Column) بررسی نمایید که Primary Key Table با tblAnbar و Foeign Key Table با tblAnbarKalaGroup برابر باشند اینها دوجدولی هستند که ارتباط بین آنها برقرار خواهد شد که Primary Key Table جدول پدر و Foeign Key Table فرزند خواهد بود

    حالا باید فیلد های رابط انتخاب شوند که قبلا به این نتیجه رسیده ایم که فیلد های Code خواهند بود پس بررسی نمایید در جدول (دوستونی) پایینی در هر دو طرف Code انتخاب شده باشد. اگر چنین نبود روی آن کلیک و از لیست باز شو Code انتخاب نماییید
    برای اعمال رابطه در هردو پنجره دکمه Ok را بزنید
    جهت تکمیل عملیات Ctrl+S را زده و دیگرام را با نام dgrWorkWithDB ذخیره کنید

    سایر رابطه ها را برطبق لیست زیر ایجاد کنید

    برای نمونه رابطه فوف که به صورت از tblAnbar به tblAnbarKalaGroup و فیلدهای Code را به صورت زیر نوشته ایم:

    tblAnbar.Code >> tblAnbarKalaGroup.Code

    لیست روابط:


    tblAnbar.Code >> tblAnbarKalaInput.ToAnbar
    tblAnbar.Code >> tblAnbarKalaOutput.FromAnbar
    tblKalaGroup.Code >> tblAnbarKalaGroup.KalaGroup
    tblKalaGroup.Code >> tblAnbarKala.KalaGroup
    tblKala.Code >>tblAnbarKalaInput.KalaCode
    tblKala.Code >>tblAnbarKalaOutput.KalaCode
    tblMoshtari.Code >> tblAnbarKalaInput.Moshtari.Code
    tblMoshtari.Code >> tblAnbarKalaOutput.Moshtari.Code
    tblUser.UserName >> tblUserDetail.UserName
    tblUser.UserName >> tblUserPremission.UserName
    tblPremissionList.Premission >> tblUserPremission.Premission


    اگر تمام مراحل فوق را با موفقیت انجام داده باشید تقریبا کار با پایگاه داده تکمیل و قابل استفاده است
    و باید خود را کم کم آماده آشنای با اصطلاحات مورد استفاده در کدنویسی کرده و کار را با کد نویسی در VB.NET ادامه دهیم.
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 25 آبان 1391 در 12:03 عصر

  10. #10
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    اصطلاحات و نام ها مورد استفاده در برنامه نویسی:

    TSQL:
    (Transact Structured Query Language)

    به معنی : زبان پرس و جوس ساخت یافته
    در حالت کلی می توان این زبان پایگاه داده برای ارتباط با آن است پس باید گفت برای ایجاد رابطه با هر کس و هر چیزی ابتدا باید زبان او را دانست
    این شامل دستور یا دستوراتی است ما آن را بر روی پایگاه داده اجرا و اطلاعاتی را به پایگاه داده ارسال یا از آن دریافت می کنیم

    اشیاء دات نت:

    Connetion:
    مسول ایجاد پل ارتباطی بین برنامه ما و پایگاه داده است که می توان آن را به تونلی تشبیه کرد که اطلاعات توسط آن بین برنامه و
    پایگاه داده رد و بدل می شود

    Connection String:

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

    Transaction:

    تراکنش در واقع بیشتر در جاهایی کاربرد دارد که نیاز است تا مجموعه ای از دستورات و کد ها پشت سر هم انجام شده و همه آنها باید با موفقت همرا باشند
    برای مثال (در حات خیلی ساده) برای حذف یک کاربر ابتدا باید مجوز های آن از جدول مجوز کاربران حذف و سپس کاربر از جدول اصلی حذف شود
    پس عملیات در صورتی موفق است که هر دو عملیات با موفقت همرا باشند
    برای همین هر دو در داخل یک تراکنش اجرا و تغییرات بر پایگاه داده زمانی به صورت قطعی اعمال می شود که هر دو با موفقیت اجرا شده باشند

    Commit-RollBack:

    در یک تراکنش چنانچه کل عملیات موفق آمیز بوده باشد با صدا زدن Commit تغییرات به صورت قطعی بر پایگاه داده اعمال می شود
    اما چنانچه یک یا چند عملیات ناموفق باشند یا ما به هر دلیلی نخواهیم تغییرات اعمال شود تغییرات را لغو(RollBack) خواهیم کرد
    توجه داشته باشید اگر یک تراکنش ایجاد شده و Commit نشود با بسته شد ارتباط RollBack اتفاق خواهد افتاد

    DataTable:

    محفظه ای است که اطلاعات یک جدول را استخراج و در داخل آن نگه خواهیم داشت(توجه داشته باشید که این شئی در صورت نیاز می تواند با کد نویسی ایجاد و پر شود)

    DataVeiw:

    همانند یک View پایگاه داده عمل کرده و نما هایی سفارشی از یک DataTable را ایجاد می کند
    نکته: ما از این شیئ در کد نویسی استفاده نخواهیم کرد و فقط جهت آشنایی شما بیان گردید

    DataRow:
    معادل یک رکورد در پایگاه داده بوده و یک DataTable از مجموع آنها حاصل می شود

    DataColumn:

    معادل یک فیلد در پایگاه داده بود و Row از مجموع یک یا چند ستون(Column) تشکیل می شود

    DataSet:
    محفظه ای است برای نگهداری DataTable ها

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

    DataAdapter:

    همانند یک Command عمل می کند ولی دارای امکانات بیشتری و توابع و متد های مفیدی زیادی می باشد


    Datareader:
    توسط این تابع اطلاعات جدولی را می توانید از پایگاه داده بخواند
    اما این شیئ دو ایراد مهم دارد
    1-با آن اطلاعات را رکورد به رکورد و فقط به سمت جلو می توان خواند که معمولا در داخل یک حلقه مورد استفاده قرار می گیرد(در واقع خواصیتی همانند متد ReadLine در کار با فایل ها دارد!)

    2-در هنگام استفاده از این شئی از لحظه ارتباط با پایگاه داده تا اتمام دریافت و پردازش اطلاعات اتصال باید همچنان با پایگاه داده برقرار باشد(اتلاف منابع!)

    نکته: ما از این شیئ در کد نویسی استفاده نخواهیم کرد و فقط جهت آشنایی شما بیان گردید
    آخرین ویرایش به وسیله فرید نجفلو : سه شنبه 08 فروردین 1391 در 00:57 صبح

  11. #11
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    رشته اتصال(Connection String) چیست؟

    رشته اتصال یکی از مشکلات حاد برنامه نویسان مبتی است حتی طبق سوال هایی که در سایت بعضی از دوستان دارند حالت سردر گمی و عدم درک
    را القا می کند

    در واقع رشته اتصال یکی از مهمترین و در عین حال ساده ترین مسائل برنامه نویسی پایگاه داده است

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

    برای مثال چند خاصیت از شئی SqlClint.SqlConnectionStringBiulder را که ابزاری جهت ایجاد ، تغییر و مدیریت رشته اتصال است را بررسی می کنیم

    -- DataSource:

    این خاصیت را می توان مهمترین خاصیت بیان نمود که اکثر ابهامات هم از همین مورد نشئات می گیرد

    این خاصیت معرف محل و نام سروری است که قصد اتصال به آن را داریم

    * محل و نام سرور چیست؟

    منظور از محل سرور رایانه ای است که سرور برروی آن نصب شده است.
    محل سرور به دو دسته تقسیم می شود:

    1-محلی:
    یعنی سرور روی همان رایانه ای قرار دارد که هم اکنون برنامه ما در آن اجرا می شود
    تعریف محل سرور محلی روش های گوناگونی دارد که به چند مورد آنها عبارتند از:

    *** استفاده از کلمه (LOCAL)
    *** استفاده از نقطه "."
    *** استفاده از نام رایانه (برای مثال MY-PC-NAME)
    *** استفاده از IP لوپ بک 127.0.0.1 (توصیه نمی شود)
    *** استفاده از IP واقعی رایانه در شبکه(برای نمونه IP مشهور 192.168.0.1) (توصیه نمی شود)

    2-راه دور(Remote):

    این سرور در جایی غیر از رایانه ای که برنامه ما در حال اجرا است قرار دارد
    تعیین محل سرور راه دور نیز متنوع است که چند نمونه ذکر می شود:
    *** استفاده از نام رایانه در شبکه (REMOTE-PC-NAME) (ارجه ترین گزینه)
    *** استفاده از IP(مثال 192.168.0.2)
    *** استفاده از آدرس (مثال www.Barnamenevis.org) البته این مورد معمولا آدرس سایت نیست بلکه سرور یک آدرس به ناکاربری و گذرواژه ارئه می کند تا از آن استفاده شود
    2-نام سرور:

    سرور به صورت بی نام (گاها پیش فرض نیز گفته می شود) و با نام نصب می گردد(نام حین نصب به سرور داده شده و بعد از نصب نیز قابل تغییر است اما تغییر نام یک سرور عملی غیر متعارف ولی مجاز تلقی می شود )

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

    اگر سرور داری نام باشد آدرس آن عبارت است از محل سرور باضافه یک ممیز وارون ( \ ) و نام سرور برای مثال نام پیش فرض جهت نسخه Express به این صورت است

    (LOCAL)\SQLEXPRESS

    و یا
    .\SQLEXPRESS


    -- InitialCatalog:

    پایگاه داده ای است که قصد ارتباط با آن را داریم
    در صورتی که فعلا پایگاه داده ما موجود نیست(در ادامه اجرای برنامه ساخته خواهد شد) و یا فعلا مشخص نیست(کاربر از بین چند پایگاه
    داده یکی از آنها را معرفی خواهد کرد) و یا هر دلیل دیگری میتوان آن را خالی گذاشت یا در حالت بهتر نام پایگاه داده پیش فرض و
    همیشه موجود یعنی master را وارد نمود (البته در مواردی همچون اتصال به پیاگاه داده موجود در اینترنت معمولا دسترسی به پایگاه داده master مجاز نمی باشد در چنین مواردی جنبه احتیاط را فراموش نکنید زیرا ممکن است با اختلاط کمی اشتباه برنامه شما قبل از شروع قفل شود!!!)

    -- UserID و Password:

    اگر برای ورود به سرور نیاز به نام کاربری و کلمه عبور باشد مقادیر این پارامتر ها را با نام کاربری و کلمه عبور معتبر مقدار دهی
    می کنیم(در حالت MIXED MODE)

    -- IntegratedSecurity:

    چنانچه نوع اعتبار سنجی سرور از نوع ویندوزی باشد یعنی کاربر سرور همان کاربری است که به ویندوز وارد شده است و نیازی به ارائه نام کاربری و کلمه عبور نمی باشد
    در این حالت مقدار این پارامتر TRUE و در غیر این صورت FALSE خواهد بود

    توجه کنید در صورتی که این پارامتر TRUE باشد از بکارگیری پارامتر های UserID و Password چشم پوشی خواهد شد!

    توصیه: قویا توصیه میشود در حالت شبکه(سرور راه دور) از حالت MIXED MODE جهت امنیت از کلمات عبور مطمئن و طولانی استفاده شود

    ConnectTimeout:

    مدت زمانی است به ثانیه که مهلت اجرای یک دستور ارسالی را مشخص می کند
    اگر دستور در این مدت پاسخی را برنگرداند با یک خطای Timeout مواجه خواهید شد
    این مدت زمان باید طوری تنظیم شود که نه دستورات زمان بر(کارهایی مثل انتقال فایل) مهلت اجرا نداشته باشند و نه اینکه در هر ایجاد خطا کاربر را به مدت طولانی منتظر نگه داید!

    نکته:اگر این مقدار با صفر تنظیم شود به معنی این است که اجرای دستورات محدویت زمانی ندارند و در اینصورت ممکن شرایطی پیش آید که مجبور باشید تا ابد منتظر بمانید!

    -- ConnectionString:

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


    شیئ SqlConnectionStringBiulder دارای خصوصیات و متدهای بیشری است ولی موارد بالا مهمترین و پر کاربرترین آنا هستند

    (در فصل بعد کد نویسی را باهم از همین رشته اتصال شروع خواهیم کرد)
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 25 آبان 1391 در 21:18 عصر

  12. #12
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    قوانینی را برای عدم گسستگی کد های خود داشته باشید:

    به این فکر کنید که هر فرم ، تابع ، متد ، روال رویدتد و ... برای خود دستورات TSQL رو ایجاد و اجرا کند شما چگونه می توانید اتصالات به پایگاه داده را مدیریت کنید؟

    پس ما توابع متد هایی را تعریف می کنیم که تنها مجاری ارتباط با پایگاه داده باشند
    یعنی:
    1- هیچ کدی حق باز کردن ارتباط با پایگاه داده را ندارد مگر توسط تابع معرفی شده

    یعنی به جز در این توابع ما نباید هیچ جایی از برنامه کد هایی شبیه این را ببینیم:


    SqlConnection.Open()
    SqlDataAdapter1.Fill(X)
    SqlCommand1.ExecuteNonQuery()
    SqlCommand1.ExecuteReader()
    SqlCommand1.ExecuteScalar()


    البته موارد استثنایی مثلا در مورد SqlConnection.Open که فعلا جای بحث آن نیست!

    2-هر کد دستورات TSQL خود را تولید می کند(تقسیم وظایف)

    برای مثال در صفحه تعریف مشتری وجود دستوری که کاربری را حذف یا اضافه می کند غیر قابل قبول است
    البته اصول کار اینه که همه کاری های ما شئی گرا بوده و هر بخش کلاس(های) خود با توبع و متد های لازم را داشته باشه

    3-سعی شود توابع و متد های عمومی اعلانی طوری تعریف شوند که همه نیاز های ما را پوشش دهند در واقع سایر کد های برنامه را پوشش دهند

    برای مثال اگر ما تابعی را برای اجرای دستورات SQL در نظر گرفته باشیم که در داخل آن یک تراکنش ایجاد و پس از اجرا اعمال(Commit) می شود همه دستورات (از جمله دستورات ایجاد پایگاه داده نخواهند توانست از آن استفاده کنند چون این نوع دستورات در داخل تراکنش قابل اجرا نیستند!)

  13. #13
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ایجاد پروژه و کلاس های اولیه :

    ایجاد پروژه:

    جهت ایجاد پروژه ، ویژوال استدیو را اجرا و در صفحه Start Page بر روی New Project کلیک کنید(یا از منوی File گزینه New Project را انتخاب کنید)
    در پنجره باز شده از لیست باز شو بالا .Net Framework 3.5 را انتخاب کنید
    بررسی نمایید که از گره های سمت چپ گره Visual Basic انتخاب شده باشد.
    از قسمت میانی پنجره نوع پروژه را Windows Forms Application انتخاب کنید
    در مقابل Name نام پروژه یعنی WorkWithDB را نوشته و بر روی دکمه OK کلیک کنید

    ایجاد پوشه های گروه بندی:

    برای ایجاد یک پوشه در پروژه روی نام پروژه در Solution Explorer کلیک راست و از منوی بازشده Add و سپس New Folder را انتخاب می نماییم
    برای ایجاد یک پوشه فرعی روی پوشه در Solution Explorer کلیک راست و از منوی بازشده Add و سپس New Folder را انتخاب می نماییم

    به روش های بالا پوشه های زیر را به پروژه اضافه نمایید:

    Class
    Class\App
    Class\DB
    Form
    Form\App
    Form\DB


    از این پو شه ها جهت گروه بندی کلاس ها و فرم های پروژه جهت راحتی در مدیریت و بکارگیری از آنها استفاده خواهد شد
    نکته:جهت جابجایی یک کلاس یا فرم در بین پوشه ها در Solution Explorer کلاس یا فرم مورد نظر را توسط موس گرفته ، کشیده و بر روی پوشه مورد نظر رها کنید


    ایجاد کلاس های اولیه :

    دو کلاس به نام های SqlMgr و Publics به پروزه اضافه کنید
    جهت انجام این کار کلید های Ctrl+Shift+A را فشرده و از پنجره باز شده گزینه Class را انتخاب نام کلاس را وارد و تایید کنید
    کلاس SqlMgr را به پوشه Class\DB و کلاس Publics را به پوشه Class\App انتقال دهید

    تنظیمات پروژه:

    در پنجره Slotution Explorer بر روی نام پروژه کلیک راست و Properties را انتخاب نمایید
    در پنجره باز شده وارد برگه Application شوید
    از لیست باز شو ShutDownMode گزینه When last form closes را انتخاب نمایید

    از برگ Refrence این کلاس را در سطح پروژه Import کنید
    در جعبه متن WorkWithDB.SqlMgrرو نوشته و دکمه Add User Import رو بزنید
    دوباره در جعبه متن WorkWithDB.Publicsرو نوشته و دکمه Add User Import رو بزنید

    در نهایت کلیدهای Ctrl+Shift+S را فشرده و پروژه را در مسیر دلخواه ذخیره کنید
    آخرین ویرایش به وسیله فرید نجفلو : سه شنبه 08 فروردین 1391 در 20:12 عصر

  14. #14
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ایجاد توابع و متغیر های عمومی و زیر بنایی:

    برای شروع کار برنامه نویسی نیازمند تعدادی توابع و متغیر های عمومی هستیم که باید ایجاد شوند(یکی از دلایل این کار همان توضیحات قسمت "قوانینی را برای عدم گسستگی کد های خود داشته باشید" می باشد)

    سعی شده توابع رو طوری نوشته شود که علاوه بر امکان استفاده در همه شرایط استفاده از آنها راحت باشد (به عنوان مثال به SqlRunCmd توجه کنید که می تونید با یک دستور TSQL از اون استفاده کنید و هم می تونید از سایر امکانات هم به صورت اختیاری استفاده کنید)

    ممکن است این توابع در آینده اصلاح شوند و تعدادی نیز در مکان مناسبی از مطالب اضافه خواهند شد
    توابع کاندیدای اصلاح با "غیر فعال" علامت گذاری شده اند (برای نمونه تابع بسیار مهم و حیاتی Loader)
    توابع در حال حاضر به دو قسمت (کلاس) تقسیم شده اند که یک کلاس جهت کار های کاملا مربوط به پایگاه داده بود و دیگری توابع و متغیر های عمومی می باشد
    تا حد امکان توابع و متغیر ها به صورت خود توضیح (Self-document) می باشند (که از XML-Documention استفاده شده است)

    هر یک از متغیر ها و توابع در صورت نیاز در محل مناسب توضیح داده خواهد شد

    کد های زیر را در کلاس های مربوطه وارد کنید:


    ''' <summary>
    ''' کلاس متد ها و توابع عمومی مورد نیاز
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Publics
    #Region "متغیر ها"
    ''' <summary>
    ''' نام کاربر جاری
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared CurrentUserName As String = ""
    ''' <summary>
    '''ذخیره کننده خطا های برای انتقال بین روال ها و توابع
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ErrorCache As String = ""
    ''' <summary>
    ''' نام پرونده ثبت خطا ها
    ''' </summary>
    ''' <remarks></remarks>
    Public Const ErrorLogFileName As String = "WorkWithDB_LogFile.Log"
    #End Region
    #Region "توابع و متد ها"
    ''' <summary>
    ''' این متد اجرای برنامه را از صفحه نخست دریافت و ادامه کارها را بر عهده می گیرد
    ''' </summary>
    ''' <remarks>غیر فعال است</remarks>
    Public Shared Sub Loader()
    Try
    'انجام کار های پیش نیاز

    'فراخوانی فرم دریافت اطلاعات پایگاه داده

    'فراخوانی فرم ورود کاربران

    'فراخوانی فرم اصلی

    'انجام کار های مورد نیاز بعدی
    Catch ex As Exception
    MsgBox("خطا در بارگذاری برنامه!" & vbNewLine & ex.Message, _
    MsgBoxStyle.Critical + MsgBoxStyle.MsgBoxRtlReading + MsgBoxStyle.MsgBoxRight, _
    "خطلای جدی")
    AddError(ex.Message)
    End
    End Try
    End Sub
    ''' <summary>
    ''' کدگذاری یک رشته متنی
    ''' </summary>
    ''' <param name="InputStr">رشته جهت کدگذاری</param>
    ''' <returns></returns>
    ''' <remarks>غیر فعال است</remarks>
    Public Shared Function StringCoding(InputStr As String) As String
    Return InputStr
    End Function
    ''' <summary>
    ''' بازیابی رشته کد شده
    ''' </summary>
    ''' <param name="InputStr">رشته کد شده</param>
    ''' <returns></returns>
    ''' <remarks>غیر فعال است</remarks>
    Public Shared Function StringDecoding(InputStr As String) As String
    Return InputStr
    End Function
    ''' <summary>
    ''' بررسی صحت نام کاربری و کلمه عبور
    ''' </summary>
    ''' <param name="UserName">نام کاربری وارد شده</param>
    ''' <param name="PassWord">کلمه عبور وارد شده</param>
    ''' <param name="CostumeConnStr">رشته اتصال سفارشی غیر از رشته اتصال عمومی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CheckUserNamePassWord(ByVal UserName As String, _
    ByVal PassWord As String, _
    Optional ByVal CostumeConnStr As String = "") As Boolean
    Return True
    End Function
    ''' <summary>
    ''' بررسی مجوز های کاربر
    ''' </summary>
    ''' <param name="Premissions">لیست مجوز های درخواستی</param>
    ''' <param name="UserName">نام کاربری-درصورت خالی بودن کاربر جاری</param>
    ''' <param name="CostumeConnStr">رشته اتصال سفارشی غیر از رشته اتصال عمومی</param>
    ''' <returns></returns>
    ''' <remarks>غیر فعال است</remarks>
    Public Function CheckUserPremission(ByVal Premissions As List(Of String), _
    Optional ByVal UserName As String = "", _
    Optional ByVal CostumeConnStr As String = "") As Boolean
    Return True
    End Function
    ''' <summary>
    ''' اضافه كردن يك خطا به محفظه خطاها
    ''' </summary>
    ''' <param name="strError">خطاي مورد نظر - الزامي</param>
    ''' <remarks></remarks>
    Public Shared Sub AddError(ByVal strError As String)
    Try
    If strError.Length = 0 Then Exit Try
    If ErrorCache.Length = 0 Then
    ErrorCache = strError
    Else
    ErrorCache = ErrorCache & vbNewLine & strError
    End If
    'نوشتن دلیل خطا در یک فایل سابقه جهت استفاده های بعدی
    'این فایل در عملیات پشتیبانی نرم افزار فوق العاده مفید خواهد بود
    Dim LogStr As String = ""
    LogStr &= PersianDate
    LogStr &= vbTab & TimeOfDay.ToString("HH:mm:ss")
    If GlobalConnectionString IsNot Nothing Then
    LogStr &= vbTab & GlobalConnectionString.DataSource
    LogStr &= "\" & GlobalConnectionString.InitialCatalog
    End If
    LogStr &= vbTab
    If CurrentUserName <> "" Then
    LogStr &= CurrentUserName
    Else
    LogStr &= "No User"
    End If
    LogStr &= vbTab & strError
    LogStr &= vbNewLine
    Dim ErrorFilePath As String = ""
    Dim LogFile As New Logging.FileLogTraceListener
    LogFile.BaseFileName = ErrorLogFileName
    LogFile.MaxFileSize = (2 ^ 20) * 10 ' 10 Megabyte
    LogFile.Location = Logging.LogFileLocation.Custom
    LogFile.CustomLocation = Application.StartupPath
    LogFile.Write(LogStr)
    LogFile.Close()
    Catch ex As Exception
    End Try
    End Sub
    ''' <summary>
    ''' برگردان تاریخ میلادی به شمسی
    ''' </summary>
    ''' <param name="InDate">تاریخ میلادی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function PersianDate(Optional InDate As Date = Nothing) As String
    Try
    If InDate.Year <= 1 Then InDate = Now
    Dim PClndr As New Globalization.PersianCalendar
    Dim DateInIran As String = PClndr.GetYear(InDate)
    DateInIran &= "/" & Strings.Right(("0" & PClndr.GetMonth(InDate)), 2)
    DateInIran &= "/" & Strings.Right(("0" & PClndr.GetDayOfMonth(InDate)), 2)
    Return DateInIran
    Catch ex As Exception
    Return ""
    End Try
    End Function

    ''' <summary>
    ''' برگردان تاریخ شمسی به میلادی
    ''' </summary>
    ''' <param name="InDate">تاریخ شمسی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GregorianDate(InDate As String) As String
    If InDate.Length <> 10 Then Return ""
    Dim Year As Integer = Mid(InDate, 1, 4)
    If Year < 1300 OrElse Mid(InDate, 1, 4) > 1500 Then Return ""
    Dim Month As Integer = Mid(InDate, 6, 2)
    If Not IsNumeric(Month) OrElse Month > 12 OrElse Month < 1 Then Return ""
    Dim Day As Integer = Mid(InDate, 9, 2)
    If Day < 1 OrElse Day > 31 Then Return ""
    Try
    Dim PClndr As New Globalization.PersianCalendar
    Return PClndr.ToDateTime(Year, Month, Day, 1, 1, 1, 1).ToString
    Catch ex As Exception
    Return ""
    End Try
    End Function
    ''' <summary>
    ''' تعیین اینکه تاریخ شمسی معتبر است یا نه
    ''' </summary>
    ''' <param name="InDate">تاریخ شمسی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CheckDate(InDate As String) As Boolean
    Try
    Return GregorianDate(InDate) <> ""
    Catch ex As Exception
    Return False
    End Try
    End Function
    #End Region
    End Class



    Imports System.Data.SqlClient
    ''' <summary>
    ''' کلاس مدیریت کار با پایگاه داده
    ''' </summary>
    ''' <remarks></remarks>
    Public Class SqlMgr
    ''' <summary>
    ''' ابزار مدیریت رشته اتصال عمومی
    ''' </summary>
    ''' <remarks>فراموش نکنید که اگر تفییری در پارامتر ها دادید رشته اتصال جدید را به نمونه اتصال عمومی نسبت دهید</remarks>
    Public Shared ReadOnly GlobalConnectionString As New SqlConnectionStringBuilder
    ''' <summary>
    ''' نمونه اتصال عمومی و پیش فرض جهت استفاده در ل برنامه
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly GlobalConnection As New SqlConnection
    ''' <summary>
    '''DataTable و پر کردن یک SQL دریافت دستور
    ''' </summary>
    ''' <param name="TSqlCmd">دستور انتخاب - الزامی</param>
    ''' <param name="Conn">یک اتصال سفارشی پایگاه داده - اختیاری</param>
    ''' <param name="Transaction">تراكنش موجود براي اتصال فرستاده شده - اختیاری</param>
    ''' <returns>ِجدول پر شده</returns>
    ''' <remarks></remarks>
    Public Shared Function SqlFillTable(ByVal TSqlCmd As String, _
    Optional ByRef Conn As SqlConnection = Nothing, _
    Optional ByRef Transaction As SqlTransaction = Nothing, _
    Optional ByRef Commander As SqlCommand = Nothing, _
    Optional ByVal DontCloseConnection As Boolean = False, _
    Optional ByVal DontSetCommanderText As Boolean = False) As DataTable
    Try
    'مقدار دهی به پارامتر ها رد صورتی که ارسال نشده باشند
    '////////////////////////////////////////////////////////////////
    If Conn Is Nothing Then Conn = GlobalConnection
    If Not OpenConn(Conn) Then Throw New Exception("")
    If Conn.State <> ConnectionState.Open Then Throw New Exception("")
    Dim Result As New DataTable
    If Commander Is Nothing Then
    Commander = Conn.CreateCommand
    Else
    Commander.Connection = Conn
    End If
    If Not DontSetCommanderText Then
    Commander.CommandText = TSqlCmd
    End If
    If Transaction IsNot Nothing Then
    Commander.Transaction = Transaction
    End If
    '////////////////////////////////////////////////////////////////
    Dim DtAdp As New SqlDataAdapter
    DtAdp.SelectCommand = Commander
    DtAdp.Fill(Result)
    Return Result
    Catch ex As Exception
    AddError(ex.Message)
    Return Nothing
    Finally
    If Not DontCloseConnection Then CloseConn(Conn)
    End Try
    End Function
    ''' <summary>
    '''و اجرای آن SQL دریافت دستور
    ''' </summary>
    ''' <param name="TSqlCmd">دستور انتخاب - الزامی</param>
    ''' <param name="Conn">یک اتصال سفارشی پایگاه داده - اختیاری</param>
    ''' <param name="Transaction">تراكنش موجود براي اتصال فرستاده شده - اختیاری</param>
    ''' <param name="Commander">يك مجري دستور - اختياري</param>
    ''' <param name="DontCloseConnection">بسته نشدن اتصال پس از اجراي دستور - اختیاری</param>
    ''' <param name="DontCommit">عدم تاييد - اعمال تراكنش - اختیاری</param>
    ''' <param name="DontSetCommanderText">دستور به مجري الصاق نشود - زماني كاربرد دارد كه مجري فرستاده شود- -اختياري</param>
    ''' <returns>ِیک مقدار بولی که نشانگر موفقت یا عدم موفقیت اجرا خواهد بود</returns>
    ''' <remarks></remarks>
    Public Shared Function SqlRunCmd(ByVal TSqlCmd As String, _
    Optional ByRef Conn As SqlConnection = Nothing, _
    Optional ByRef Transaction As SqlTransaction = Nothing, _
    Optional ByRef Commander As SqlCommand = Nothing, _
    Optional ByVal DontCloseConnection As Boolean = False, _
    Optional ByVal DontCommit As Boolean = False, _
    Optional ByVal DontSetCommanderText As Boolean = False) As Boolean
    Try
    'مقدار دهی به پارامتر ها رد صورتی که ارسال نشده باشند
    '////////////////////////////////////////////////////////////////
    If Conn Is Nothing Then Conn = GlobalConnection
    If Not OpenConn(Conn) Then Throw New Exception("")
    If Conn.State <> ConnectionState.Open Then Throw New Exception("")
    Dim Trans As SqlClient.SqlTransaction
    If Transaction Is Nothing Then
    Trans = Conn.BeginTransaction
    Else
    Trans = Transaction
    End If
    If Commander Is Nothing Then
    Commander = Conn.CreateCommand
    Else
    Commander.Connection = Conn
    End If
    If Not DontSetCommanderText Then
    Commander.CommandText = TSqlCmd
    End If
    '////////////////////////////////////////////////////////////////
    Commander.Transaction = Trans
    Commander.ExecuteNonQuery()
    If Not DontCommit Then Trans.Commit()
    Return True
    Catch ex As Exception
    AddError(ex.Message)
    Return False
    Finally
    If Not DontCloseConnection Then CloseConn(Conn)
    End Try
    End Function
    ''' <summary>
    '''و اجرای آن بدون تراکنش SQL دریافت دستور
    ''' </summary>
    ''' <param name="TSqlCmd">دستور انتخاب - الزامی</param>
    ''' <param name="Conn">یک اتصال سفارشی پایگاه داده - اختیاری</param>
    ''' <param name="DontCloseConnection">بسته نشدن اتصال پس از اجراي دستور - اختیاری</param>
    ''' <returns>ِیک مقدار بولی که نشانگر موفقت یا عدم موفقیت اجرا خواهد بود</returns>
    ''' <remarks></remarks>
    Public Shared Function SqlRunCmdwithoutTrans(ByVal TSqlCmd As String, _
    Optional ByRef Conn As SqlConnection = Nothing, _
    Optional ByVal DontCloseConnection As Boolean = False) As Boolean
    Try
    If Conn Is Nothing Then Conn = GlobalConnection
    If Not OpenConn(Conn) Then Throw New Exception("")
    If Conn.State <> ConnectionState.Open Then Throw New Exception("")
    Dim Cmd = Conn.CreateCommand
    Cmd.CommandText = TSqlCmd
    Cmd.ExecuteNonQuery()
    Return True
    Catch ex As Exception
    AddError(ex.Message)
    Return False
    Finally
    If Not DontCloseConnection Then CloseConn(Conn)
    End Try
    End Function
    ''' <summary>
    ''' باز کردن اتصال
    ''' </summary>
    ''' <param name="Conn">اتصال مورد نظر</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function OpenConn(ByRef Conn As SqlConnection) As Boolean
    Try
    If Not (Conn.State = ConnectionState.Connecting OrElse Conn.State = ConnectionState.Open) Then
    Conn.Open()
    End If
    Return True
    Catch ex As Exception
    AddError(ex.Message)
    Return False
    End Try
    End Function
    ''' <summary>
    ''' بستن اتصال
    ''' </summary>
    ''' <param name="Conn">اتصال مورد نظر</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CloseConn(ByRef Conn As SqlConnection) As Boolean
    Try
    If Conn.State = ConnectionState.Connecting OrElse Conn.State = ConnectionState.Open Then
    Conn.Close()
    End If
    Return True
    Catch ex As Exception
    AddError(ex.Message)
    Return False
    End Try
    End Function
    ''' <summary>
    '''SQL آماده کردن متن براي استفاده در دستورات
    ''' </summary>
    ''' <param name="strIn">متن برای تبدیل</param>
    ''' <returns>متن با تک نقل قول در دو طرف آن</returns>
    ''' <remarks></remarks>
    Public Shared Function PrepStrToSql(ByVal strIn As String) As String
    Try
    Dim Result As String
    Result = "'" & strIn.Trim & "'"
    Return Result
    Catch ex As Exception
    AddError(ex.Message)
    Return strIn
    End Try
    End Function
    End Class
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 10 فروردین 1391 در 00:58 صبح

  15. #15
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    رشته اتصال(Connction String)و اتصال (Connection) را چگونه و کجا تعریف و مقدار دهی کنیم؟

    قبل از ادامه بحث ممکن است سوالی برای دوستان پیش آید که چرا اول رشته اتصال تعریف شد سپس این همه کد ارائه و دوباره به این مرحله وارد شدیم (چیزی شبیه به خانه اول)

    اول : اینکه مبحث قبلی رشته اتصال مربوط به تعریف و اصطلاحات بوده و نیازی به کد نداشتند و از این قسمت به بعد است که با برنامه نویسی واقعی و مشکلات آن درگیر خواهیم شد

    دوم: به دلیل جلوگیری از تکه تکه شدن مطالب و از این شاخه به آن شاخه پریدن (برای مثال در بین ایجاد یک متد در فرم به کلاس ها رفته و یک تابع جدید ایجاد و دو باره به فرم برگشت!) و از دست دادن رشته بحث ، آن تعداد از توابع و متد ها که از حالا قابل پیش بینی بوده و می تواند در بین همه نرم افزار های ما مشترک باشد ارائه شده و همانطور که گفته شد در صورت نیاز هم در محل خود توضیح داده خواهد شد!




    با توجه به اینکه رشته اتصال یکی از زیر بناهای سایر قسمت ها است ابتدا آن را بررسی و به برنامه اضافه خواهیم کرد
    نکته:رشته اتصال به قدری مهم است که به تنهایی یک فرم را در برنامه فقط برای خود اختصاص داده و مهمتر از آن این فرم اولین فرم کاربردی خواهد بود که کاربر می بیند!

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

    بدلیل اینکه رشته اتصال باید در تمام نقاط برنامه در دسترس باشد آن را به صورت Public و جهت عدم نیاز به نمونه سازی از کلاس(NEW) به همراه Shared در کلاس SqlMgr تعریف و اعلان می شود!

    ''' <summary>
    ''' کلاس مدیریت کار با پایگاه داده
    ''' </summary>
    ''' <remarks></remarks>
    Public Class SqlMgr
    ''' <summary>
    ''' ابزار مدیریت رشته اتصال عمومی
    ''' </summary>
    ''' <remarks>فراموش نکنید که اگر تغییری در پارامتر ها دادید رشته اتصال جدید را به نمونه اتصال عمومی نسبت دهید</remarks>
    Public Shared ReadOnly GlobalConnectionString As New SqlConnectionStringBuilder


    کجا رشته اتصال را مقدار دهی کنیم؟

    در بیشتر موارد دیده می شود که دوستان به این روش برنامه رو آغاز می کنند :
    آغاز برنامه توسط کاربر>> نمایش Splash >> فرم اصلی
    که این روش مناسبی نیست
    یک پیشنهاد برای نرم افزار های مربوط به پایگاه داده به این صورت است:
    اجرا توسط کاربر>> Splash>>اجرای یک متد (Sub) به عنوان Loader >> نمایش صفحه اتصال و انتخاب پایگاه داده >> اعتبار سنجی(Login) >> ورود به فرم اصلی

    Loader :

    جهت بارگذاری تنظیمات مهم و پیش فرض و امورات پیش اجرا که یکی از مهمترین این کارها دریافت یا بررسی شماره سریال محصول است که ممکن است مجبور به عدم ادامه عملیات اجرا یا اجرای آزمایشی شویم!
    در همین متد صفحه (مرحله) بعدی شروع می شود

    نمایش صفحه اتصال و انتخاب پایگاه داده :

    این محل همان جایی است که رشته اتصال رو باید دریافت کنیم که در وهله اول از تنظیمات ذخیره شده اجرا های قبلی (بعدا توضیح داده خواهد شد) خوانده شده و به کاربر اجازه تغییر آنها را می دهیم:
    حداقل اطلاعاتی که باید در این مرحله دریافت شود:

    *-نام سرور

    *-نام کاربری و کلمه عبور: جهت ورود به سرور(برای اینکه باید حالت MixedMode هم مد نظر باشد)

    *-نام پایگاه داده
    این مورد یا مستقیم توسط کاربر وارد می شود یا توسط برنامه برای مثال تمام دیتابیس هایی که نام آنها با WorkWithDB شروع می شود متعلق به برنامه ماست که در این صورت هم، باید به کاربر اجازه بدهیم دیتابیس خودشو انتخاب کنه.
    ما در ابتدا از یک پایگاه داده که دارای نام ثابتی است استفاده و در ادامه و آموزش های پیشرفته از چند پایگاه داده با قابلیت سوئیچ استفاده خواهیم کرد)

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

    اعتبار سنجی(Login):

    در این مرحله رشته اتصال ایجاد شده به فرم ورود کاربر ارسال می شود تا کاربر نام کاربری و کلمه عبور خود را برای ورود به نرم افزار وارد کند(توجه کنید که این نام کاربری و کلمه عبور جدا از کاربر متعلق به پایگاه داده بوده و شما آن را در پایگاه داده بر جدولtblUsers تعریف و ایجاد کرده اید)

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

    در غیر اینصورت پیغام (های) لازم نمایش و دوباره به صفحه قبل(دریافت رشته اتصال) برگشته یا کلا از برنامه خارج می شویم!

    ورود به فرم اصلی:

    در این مرحله اتصال به پایگاه داده انجام شده رشته اتصال آماده استفاده می باشد و عملیات مختص نرم افزار شروع می شود (که معمولا نقطه آغازین از رویداد FormLoad فرم اصلی شروع می شود!)

    اتصال (Connection):
    چون اتصال (Connection) و استدلال های بالا می باشد و وابسته به رشته اتصال است این نیز همانند رشته اتصال و در کنار آن تعریف می شود البته ذکر این نکته مهم است که اتصال همانند رشته اتصال تعریف می شود ولی نسبت به آن در مکان هایی بیشتری ظاهر خواهد شد!

      ''' <summary>
    ''' نمونه اتصال عمومی و پیش فرض جهت استفاده در ل برنامه
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly GlobalConnection As New SqlConnection
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 10 فروردین 1391 در 00:59 صبح

  16. #16
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ایجاد لایهADL کار با داده ها (Data Access Layer):

    این لایه با دستکاری داده ها مثل اضافه ، حذف و به روز رسانی آن ها سر و کار دارد که به لطف فناوری های ADO.NET بسیار آسان گردیده
    است
    به دلیل اینکه قرار بر عدم استفاده از LINQ در این بحث است!!! ما از یک کلاس DataSet جهت ایجاد این لایه استفاده خواهیم کرد
    توجه کنید همانطور که دید ما یک تعدا توابع کار با پایگاه داده را نیز ایجاد کرده ایم ولی بیشتر کار های این لایه با استفاده از
    DataSet مذکور خواهد بود و در جاهاییی که انجام عملیات با این کلاس دشوار و گاها غیر ممکن می شود از توبع استفاده خواهد شد
    از جمله این کار ها دریافت ، ایجاد و بررسی صحت رشته اتصال است چون تا زمانی که اتصال و رشته اتصال مشخص نباشد امکان استفاده از Dataset وجود ندارد
    یک مثال دیگر عملیاتی نظیر حذف و ایجاد پایگاه داده ها است(در آموزش های پیشرفته)

    ایجاد DataSet:

    جهت انجام این کار با استفاده از کلید های Ctrl+Shift+A پنجره Add New Item را باز و گره Data را از سمت چپ انتخاب کنید
    از قسمت میانی پنجره Datasetانتخاب و با نام dsWorkWithDb تایید کنید
    پروژه را ذخیره کنید

    نکته:به این Dataset که امکان کار با جداول را به صورت شیئ گرا می باشد در اصطلاح Typed DataSets می گویند.

    افزودن اشیا پایگاه داده:

    از Solutin Explorer بر روی Dataset ایجاد شده دوبار کلیک کنید تا وارد حالت طراحی شود
    از منوی Tools گزینه Connect to Database را انتخاب کرده از پنجره باز شده Microsoft SQL Server را انتخاب و تایید نمایید
    حالا شما می بایست در پنجرهAdd Coonection نام سرور و در صورت نیاز نام کاربری و کلمه عبور به سرور را وارد نمایید سپس از لیست
    باز شو select or enter database name پایگاه داده WorkWithDb_Sample1 را که قبلا توسط اسکریپ همراه پروژه ایجاد کرده اید را انتخاب کنید و تایید نمایید

    اکنون یک اتصال به این پایگاه داده به Server Explorer اضافه شده است
    گره مربوط به پایگاه داده خود را باز و گره Tables را نیز گسترش دهید
    تمام جداول را (با استفاده از Ctrl یا Shift ) انتخاب نمایید
    جداول انتخاب شده را با موس گرفته و داخل پنجره طراحی Dataset رها کنید

    پروژه را ذخیره کنید

    مقدار زیادی کار طراحی ین لایه که قبل از ظهور این تکنولوژی کار طاقت فرسایی بود انجام شده است
    دستورات TSQL مورد نیاز نیز در مکان های مناسب مطلب در همین پنجره اضافه خواهد شد

    قبل از ادامه مطلب همانطور که در قسمت های قبلی آموختید دو کلاس و فضای نامی زیر را از Properties پروژه Import عمومی نمایید

    در پنجره فوق نام کلاس WorkWithDb.dsWorkwithDb رو داخل تکست باکس نوشته و دکمه Add User Import رو بزنید
    کلاس WorkWithDb.dsWorkwithDbTableAdapters که با افزودن و ذخیره نمودن دیتاست ایجاد شده است را از لیست (معمولا در انتهای آن است) یافته تیک بزنید
    پروژه رو ذخیره کنید.



    WorkWithDb.dsWorkwithDb
    WorkWithDb.dsWorkwithDbTableAdapters


    تعریف و نمونه سازی ابزار مدیریت اتصالات این لایه:

    اعلان زیر را به کلاس SqlMgr اضافه نمایید:

        ''' <summary>
    ''' مدیریت ابزار لایه دسترسی به اطلاعات
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly AdpMgr As New TableAdapterManager



    نکته: این متغیر چون یک بار نمونه سازی شده و در ادامه نیازی به تعریف مجدد ندارد به همین دلیل به صورت ReadOnly تعریف گردید تا از تغییر آن در سایر کد ها جلوگیری شود

    نمونه سازی ابزار ها:

    چون نمونه اشیائ موجود در AdpMgr نمونه سازی نشده اند متدی را جهت نمونه سازی و تنظیم اتصالی باید که از آن استفاده کنند (اتصال عمومی ساخته شده در مراحل قبل) ایجاد می کنیم
    نکته:این متد بعد از ایجاد رشته اتصال و نسبت دادن آن به نمونه اتصال عمومی فراخوانی خواهد شد که اولین نقطه آن متد Loader خواهد بود
    این کد ها را به کلاس SqlMgr اضافه نمایید


        ''' <summary>
    '''مقدار دهی به ابزار ها
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub InitAdapters()
    Try
    AdpMgr.Connection = GlobalConnection
    AdpMgr.tblAnbarKalaGroupTableAdapter = New tblAnbarKalaGroupTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblAnbarTableAdapter = New tblAnbarTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblDbVerTableAdapter = New tblDbVerTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaGroupTableAdapter = New tblKalaGroupTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaInputTableAdapter = New tblKalaInputTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaOutputTableAdapter = New tblKalaOutputTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaTableAdapter = New tblKalaTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblMoshtariTableAdapter = New tblMoshtariTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblPremissionListTableAdapter = New tblPremissionListTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblUserDetailTableAdapter = New tblUserDetailTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblUserPremissionTableAdapter = New tblUserPremissionTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblUserTableAdapter = New tblUserTableAdapter With {.Connection = GlobalConnection}
    Catch ex As Exception
    End Try
    End Sub


    توضیحی در باره تابع:

    در هنگام ایجاد dataset برای هر جدول یک TableAdapter ایجاد می شود که وظیفه اجرای دستورت بروی هر جدول را دارد
    در ادامه مطلالب و در در جای خود دستور TSQL را به این اشیا اضافه و بعنوان متدی از داخل آنها قابل استفاده خواهیم نمود(در واقع شبیه تابع جلوه خواهند کرد)

    این اشیا به صورت تجمیع شده داخل یک کلاس دیگر به نام TableAdapterManager تعریف شده اند ولی نمونه سازی (با NEW) نشده اند
    به همین دلیل ما قبل از استفاده از آنها توسط کلمه کلیدی New آنها را نمونه سازی کرده و در همین خط هم جهت راحتی و خلا صه نویسی نمونه اتصال عمومی را به عنوان اتصالی که باید توسط آن با پایگاه داده ارتباط برقرا کنند معرفی می کنیم
    در نتیجه ما اتصال عمومی را با رشته اتصال عمومی به سمت هر پایگاه داده که نشانه رویم Dataset نیز از همان استفاده خواهد نمود (یکی از دلایلی که ما رشته اتصال و اتصال عمومی را مورد تاکید زیاد قرار داده و به صورت عمومی معرفی نمودیم در اینجا نمایان است)

    DataTable های قویا نام گذاری شده یا Strongly Named DataTable:

    وقتی شما جداول را داخل Dataset انداختید در همان حین یک DataTable نیز برای آنها با نام خودشان ایجاد شد
    ولی چند تفاوت عمده میان آنها و یک DataTable های عادی وجود دارد و آن دستیابی به فیلد های جدول بع عنوان یکی از خاصیت های این
    DataTableمی باشد برای مثال وقتی شما یک پرسجو از جدول tblUser را توسط AdpMgr.tblUserTableAdapter و تابع GetData انجام دادید
    نوع بازگشتی آن tblUserDataTable و هردیف(Item) از این شیئ tblUserRow می باشد و نکته در همین آیتم است
    برای مثال برای دریافت نام اولین کاربر موجود در این مقدار برگشتی کافی است به صورت زیر بنویسید(به استفاده از نام فیلد به صورت
    یک خاصیت توجه کنید):

    MytblUserDataTable.Item(0).UserName


    همه این کارها بدون یک خط کدنویسی شما و در کمتر 5 دقیقه انجام شده است!

    نکته: این لایه رفته رفته تکمیل خواهد شد به این صورت که در برنامه نویسی هر بخش زمانی که احساس نیاز به عملیات پاگاه داده ای غیر موجود دید شد TSQL مورد نظر به TableAdapter مربوطه اضافه و مورد استفاده قرار خواهد گرفت
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 10 فروردین 1391 در 16:48 عصر

  17. #17
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ساخت فرم دریافت رشته اتصال(اولین فرم کاربردی در لایه PL):

    همان طور که متذکر شده بودیم اولین فرم کاریردی که کاربر خواهد دید همین فرم خواهد بود
    وظیفه این فرم در یافت رشته اتصال به صورت کاربر پسند است (با استفاده از کنترل ها نه دریافت مستقیم یک رشته اتصال)

    توجه نمایید که ما برنامه را از یک فرم Splash آغاز خواهیم کرد ولی چون این فرم تاثیر چندانی در کار ندارد و فقط وظیفه انتقال کنترل به متد Loader را دارد توجه زیادی به آن نشده و ما از یک Splash آماده در خود ویژوال استدیو استفاده می کنیم

    هم چنین ما در زیبا سازی رابط کاربری(فرم ها) می شود گفت کاری انجام نداده ایم زیرا انجام چنین کاری نیاز به کد نویسی ، انجام تنظیمات و ارائه توضیحات بیشتر بوده و بحث را از هدف اصلی خود دور خواهد نمود و همچنین این واقعیت هم وجود دارد که ظاهر هر نرم افزار وابستگی کامل به سلیقه و دانش برنامه نویس در طراحی دارد.

    ایجاد فرم Splash:

    پنجره Add New Item را باز ، گره Windoes Forms را انتخاب و یک Splash Screen را با نام frmAppSplash به پروژه اضافه نمایید

    از نوار ابزار یک کنترل Timer به فرم اضافه نموده و نام آن را به tmrShowDelay تغییر داده خاصیت Enable را نیز True نمایید

    نکته: از این به بعد درباره طراحی گرفیکی فرم توضیحات مفصل ارائه نشده و فقط موارد مهم و مورد نیاز به اختصار گفته شده و مستقیما وارد پنجره کد نویسی خواهیم شد زیرا ظاهر فرم ها در پروژه نمونه ارئه شده قابل مشاهده و نیازی به توضیح ندارد و ارائه توضیحات مفصل موجب اتلاف زمان گران بها و به درازا کشیدن صحبت ها خواهد شد

    حالا با کلید F7 وارد پنجره کد نویسی فرم شوید

    تمام کد های قرار گرفته در میان تعریف کلاس فرم را پاک و کد های زیر را اضافه نمایید:


    #Region "متغیر ها"
    ''' <summary>
    ''' شفافیت پنجره
    ''' </summary>
    ''' <remarks></remarks>
    Private opcty As Double = 0
    #End Region
    #Region "روال رویداد ها"
    ''' <summary>
    ''' ایجاد وقفه نمایش فرم
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub tmrShowDelay_Tick(sender As System.Object, e As System.EventArgs) Handles tmrShowDelay.Tick
    Try
    opcty += 0.02
    Me.Opacity = Math.Min(1, opcty)
    If opcty >= 2 Then
    opcty = 0
    tmrShowDelay.Stop()
    Me.Visible = False
    Loader()
    Me.Close()
    End If
    Catch ex As Exception
    Me.Visible = False
    Loader()
    Me.Close()
    Finally
    End Try
    End Sub
    Private Sub lblbarnamenevis_LinkClicked_1(sender As System.Object, e As System.Windows.Forms.LinkLabelLinkClickedEventArgs ) Handles lblbarnamenevis.LinkClicked
    Process.Start("https://barnamenevis.org/showthread.p...م-به-گام")
    End Sub
    #End Region


    نکته:تغییراتی در ظاهر و نام کنترل ها داده شده است که تاپیری در کد ها ندارند لذا از ذکر آنها خوداری می شود:

    توضیح کد:

    تنها کد مفید و همین طور مهم ، روال رویداد کنترل تایمر می باشد

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

    اولین خط فرم را از دید کاربر پنهان می نماید

    دومین خط کنترل اجرا را به تابع Loader انتقال داده و منتظر آن می ماند

    خط سوم نیز بعد اجری کامل متد مذکور وارد عمل شده و فرم Spalsh را به طور کامل خواهد بست!(در صورتی که متد Loader به برنامه خاتمه نداده باشد)

    چرا ما ابتدا Me.Close را فرخوانی و سپس اقدام به اجرای متد نمی کنیم؟

    توجه داشته باشد در حال حاضر تنها فرمی که در حال اجرا می باشد همین فرم است پس چنانچه ما اقدام به بستن این فرم نماییم بدلیل اینکه دیگر فرم در حال اجرایی وجود ندارد کل برنامه به صورت خودکار بسته و اجرا به اتمام خواهد رسید!


    تغییر متد Loader:

    حال که کنترل را به این متد واگذار می کنیم پس باید کد های مورد نیاز را به آن اضافه نماییم

    متد Loader را به صورت زیر تغییر دهید:

        ''' <summary>
    ''' این متد اجرای برنامه را از صفحه نخست دریافت و ادامه کارها را بر عهده می گیرد
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub Loader()
    Try
    'انجام کار های پیش نیاز
    InitAdapters()
    'فراخوانی فرم دریافت اطلاعات پایگاه داده
    GetConnStr:
    Dim frmDb As New frmDatabase
    Dim ConnStr As String = frmDb.ShowDialog
    frmDb.Dispose()
    If ConnStr = "" Then
    MsgBox("عملیات لغو شد!")
    Else
    MsgBox("OK" & vbNewLine & ConnStr)
    End If
    End
    'فراخوانی فرم ورود کاربران

    'فراخوانی فرم اصلی

    'انجام کار های مورد نیاز بعدی
    Catch ex As Exception
    MsgBox("خطا در بارگذاری برنامه!" & vbNewLine & ex.Message, _
    MsgBoxStyle.Critical + MsgBoxStyle.MsgBoxRtlReading + MsgBoxStyle.MsgBoxRight, _
    "خطای جدی")
    AddError(ex.Message)
    End
    End Try
    End Sub


    توضیح کد ها:

    متد InitAdapters() باید برای شما آشنا باشد! درست است این همان متدی است که در مرحله قبل ایجاد کردیم و وظیفه مقدار دهی و تنظیم ابزار های موجود در Dataset را دارد و همانجا هم وعده اجرای آن را در این متد داده بودیم!
    خط بعدی یک برچسب پرش است است که در زمان توضیح فرم ورود کاربر بررسی و مورد استفاده قرار خواهد گرفت
    در خط بعدی یک نمونه از فرم frmDatabase را ایجاد می کنیم

    و اما مهمترین خط! در این خط نمونه فرم frmDatabase فرخوانی و نتیجه بازگشتی را که یک رشته اتصال خواهد بود را در متغیر ConnStr قرار می دهیم (در ادامه به بررسی عمل کرد فرم از نقطه شروع یعنی تابع ShowDialog خواهیم پرداخت)

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

    نکته: چند خط مربوط به شرط جهت آزمایش و اطمینان از عملکرد صحیح برنامه تا این مرحله بوده و در مرحله بعدی حذف خواهد شد

    ایجاد فرم دریافت رشته اتصال:

    بالاخره به مهمترین فرم این مرحله از کار رسیدیم
    این فرم دارای چند کنترل است که وظیفه دریافت اطلاعات اساسی رشته اتصالی که ما را به پایگاه داده متصل خواهد نمود دارند(بررسی بخش UI به خودتان واگذار می شود!)

    کد های زیر را به فرم اضافه نمایید تا در ادامه به توضیح آنها بپردازیم:



    ''' <summary>
    ''' فرم مدیریت رشته اتصال به پایگاه داده
    ''' </summary>
    ''' <remarks></remarks>
    Public Class frmDatabase
    #Region "متغیر ها"
    ''' <summary>
    ''' نام پایگاه داده پیش فرض
    ''' </summary>
    ''' <remarks></remarks>
    Private ReadOnly DefultDbName As String = "WorkWithDb_Sample1"
    ''' <summary>
    ''' نام نگارش (نرم افزار) پایگاه داده
    ''' </summary>
    ''' <remarks></remarks>
    Private ReadOnly DbVerName As String = "WorkWithDb"
    ''' <summary>
    '''شماره نگارش معتبر پایگاه داده
    ''' </summary>
    ''' <remarks></remarks>
    Private ReadOnly DbVerNum As String = "1.0.0.0"
    ''' <summary>
    ''' سارنده رشته اتصال نتیجه
    ''' </summary>
    ''' <remarks></remarks>
    Private ReadOnly MyConnStrBldr As New SqlConnectionStringBuilder With {.DataSource = "Local", .InitialCatalog = DefultDbName, _
    .ConnectTimeout = 30, .UserID = "sa"}
    #End Region
    #Region "توابع و متد ها"

    ''' <summary>
    ''' نمایش فرم و دریافت اطلاعات از کاربر
    ''' </summary>
    ''' <param name="ConnStr">رشته اتصال جهت بارگذاری در کنترل ها</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shadows Function ShowDialog(Optional ConnStr As String = "") As String
    Try
    If ConnStr <> "" Then MyConnStrBldr.ConnectionString = ConnStr
    SetValues()
    Me.DialogResult = Windows.Forms.DialogResult.Cancel
    MyBase.ShowDialog()
    If Me.DialogResult = Windows.Forms.DialogResult.OK Then
    Return MyConnStrBldr.ConnectionString
    Else
    Return ""
    End If
    Catch ex As Exception
    Return False
    End Try
    End Function
    ''' <summary>
    '''مقدار دهی اولیه به کنترل ها
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub SetValues()
    Try
    cmbServer.Text = MyConnStrBldr.DataSource
    txtTimeout.Text = MyConnStrBldr.ConnectTimeout
    txtUserName.Text = MyConnStrBldr.UserID
    Catch ex As Exception
    End Try
    End Sub

    ''' <summary>
    ''' بررسی صحت اطلاعات ورودی توسط کاربر
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IsValidData() As Boolean
    Try
    Me.ErrorProvider1.Clear()
    If cmbServer.Text.Trim = "" Then
    ErrorProvider1.SetError(Me.cmbServer, "نام سرور وارد نشده است")
    Throw New Exception("نام سرور وارد نشده است!")
    End If
    If txtTimeout.Text.Trim = "" OrElse Not IsNumeric(txtTimeout.Text) Then
    ErrorProvider1.SetError(Me.txtTimeout, "مهلت اتصال وارد نشده است")
    Throw New Exception("مهلت اتصال وارد نشده است!")

    End If
    If Not chkIntegrated.Checked Then
    If txtUserName.Text.Trim = "" Then
    ErrorProvider1.SetError(Me.txtUserName, "نام کاربری وارد نشده است!")
    Throw New Exception("نام کاربری وارد نشده است")
    End If
    End If
    Return True
    Catch ex As Exception
    MsgBox("اطلاعات ورودی نا معتبر!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    Return False
    End Try
    End Function
    ''' <summary>
    ''' بررسی صحت رشته اتصال
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IsValidConnStr() As Boolean
    Try
    ErrorCache = ""
    If Not IsValidData() Then Return False
    MyConnStrBldr.ConnectTimeout = CInt(txtTimeout.Text)
    MyConnStrBldr.DataSource = cmbServer.Text.Trim
    MyConnStrBldr.IntegratedSecurity = chkIntegrated.Checked
    If chkIntegrated.Checked Then
    MyConnStrBldr.UserID = ""
    MyConnStrBldr.Password = ""
    Else
    MyConnStrBldr.UserID = txtUserName.Text.Trim
    MyConnStrBldr.Password = txtPassword.Text
    End If
    Return CheckConnetionString(ConnStr:=MyConnStrBldr.Connec tionString, DbVerName:=DbVerName, DbVerNum:=DbVerNum)
    Catch ex As Exception
    MsgBox("خطا در بررسی اتصال به پایگاه داده!" & vbNewLine & _
    ex.Message & vbNewLine & ErrorCache, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "اتصال موفق")
    Return False
    End Try
    End Function
    #End Region
    #Region "روال رویداد ها"
    Private Sub chkIntegrated_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles chkIntegrated.CheckedChanged
    grpIntegrated.Enabled = Not chkIntegrated.Checked
    End Sub
    Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
    If IsValidConnStr() Then
    Me.DialogResult = Windows.Forms.DialogResult.OK
    Me.Close()
    End If
    End Sub
    Private Sub btnTestConn_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTestConn.Click
    If IsValidConnStr() Then
    MsgBox("اتصال به پایگاه داده با موفقت انجام شد", _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "اتصال موفق")
    End If
    End Sub
    Private Sub btnCancel_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
    Me.DialogResult = Windows.Forms.DialogResult.Cancel
    Me.Close()
    End Sub
    #End Region



    توضیح کد:

    متغیر ها:

    DefultDbName : با این متغیر نام پایگاه داده ای را که ساخته ایم نگه داری می کنیم تا از پرسش آن از کاربر جلو گیری شود
    چون فعلا ما تنها با یک پایگاه داده (در هر سرور) کار خواهیم کرد یک نام ثابت برای آن اختیار و از همان جهت اتصال استفاده خواهیم نمود

    DbVerName : خواهید دید که در هنگام اعتبارسنجی پایگاه داده از این متغیر جهت شناسایی اینکه پایگاه داده مورد نظر متعلق به این نرم افزار می باشد یا نه استفاده خوایم نمود (چون در وقعیت ممکن است چند نرم افزار را با ساختار پایگاه داده مشابه ایجاد نماییم با این کار از تداخل برنامه های خود جلو گیری می کنیم!)

    DbVerNum : در هنگام اعتبار سنجی پایگاه داده پس از اینکه مشخص شد پایگاه داده متعلق به این نرم افزار است توسط این متغیر بررسی می گردد که نگارش نرم افزاری که پایگاه داده را ایجاد کرده با نگارش این نرم افزار یکسان باشند برای مثال نگارش 1 نرم افزار اقدام به باز کردن پایگاه داده نگارش 2 نرم افزار ننماید

    MyConnStrBldr : توسط این شیئ رشته اتصال موقتی را که در این فرم ایجاد و حلاجی خواهیم نمود را مدیریت و رشته اتصال آن را در صورت صحیح بودن به عنوان پاسخ به کدی که فرم را فراخوانی نموده برگشت می دهیم و در همین خط تعریف آن را مقدار دهی اولیه می نماییم

    توابع و متد ها:

    تابع ShowDialog:

    Public Shadows Function ShowDialog() As String 


    در این جا ما یک تابع نوشته ایم که تابع اصلی مربوط به فرم را پنهان و خود به جای آن معرفی خواهد نمود(البته ما می توانستیم یک تابع جدید ایجاد کنیم ولی این تابع چون مشهور و کار آن مشخص شده است برای چنین کاری بسیار مناسب می باشد)

    If ConnStr <> "" Then MyConnStrBldr.ConnectionString = ConnStr


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

    Me.DialogResult = Windows.Forms.DialogResult.Cancel 


    این یک خاصیت است که در همه فرم ها وجود دارد حتی MsgBox هم یکی از این نوع را برمی گشت می دهد ما بوسیله مقدار آن خواهیم فهمید که کاربر دکمه تایید را انتخاب کرده یا انصراف(یا فرم را بسته است) ما می تونستیم یه متغیر جداگانه برای این کار تعریف کنیم ولی از لقمه آماده استفاده کردیم

    MyBase.ShowDialog() 


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

    حال کاربر دکمه تایید رو کلیک می کند(که Windows.Forms.DialogResult.Cancelبا OK تنظیم می شود) یا انصرف می دهد که همان Cancel در جای خود باقی می ماند
    پس پنجره با ضربدر خودش یا Me.Close بسته می شود

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

    If Me.DialogResult = Windows.Forms.DialogResult.OK Then
    Return MyConnStr.ConnectionString
    Else
    Return ""
    End If


    بررسی میشود کدام دکمه زده شده و نتیجه برگشت داده می شود

    SetValuse : وظیفه مقدار دهی اولیه به کنترل ها را دارد


    IsValidData: این تابع صحت اطلاعات وارد شده توسط کاربر را بررسی می نماید که با توجه به متن های پیغام خطا ها می شود عمل کرد آن را فهمید پس نیازی به توضیح اضافی ندارد

    IsValidConnStr: این تابع ابتدا صحت اطلاعات را توسط IsValidData بررسی و سپس مقادیر را در MyConnStr در وارد می کند

    سپس رشته اتصال را برای تابع CheckConnetionString جهت بررسی می فرستد و نتیجه همان تابع را برگشت می دهد( این تابع در ادمه اضافه و بررسی خواهد شد)

    روال رویداد ها:
    این چند خط کد ساده را هم خود تجزیه تحلیل نمایید (تمرین کنید زیرا رفته رفته و زمانی که چیز های بیشتری آموختید کد های بیشتری نیز به خود شما محول خواهد شد!)

    CheckConnetionString :
    این تابع جهت بررسی یک رشته اتصال است

    ابتدا کد های مربوط به تابع را به کلاس SqlMgr اضافه نمایید
    نکته:ممکن است این سوال پیش آید که چرا ما این تابع را در همان فرم ایجاد و استفاده نمی نماییم؟
    توجه داشته باشید یکی از اصول لایه بندی این است که لایه UI نباید شامل هیچ کدی باشد که اقدام به ارتباط مستقیم با پایگاه داده می نماید
    در حالی که این تابع چیزی فراتر از آن نیز می باشد به طوری که برای خود یک Connection مجزا می سازد و مستقیما دستورات TSQL را نیز به کار می برد(از Dataset استفاده نمی کند!) درنتیجه ما به هیچ وجه مجوز استفاده از آن را در داخل یک فرم نخواهیم داشت!


        ''' <summary>
    ''' بررسی توانایی اتصال به پایگاه داده توسط یک رشته اتصال و اعتبار سنجی پایگاه داده
    ''' </summary>
    ''' <param name="ConnStr">رشته اتصال</param>
    ''' <param name="DbVerName">نام نگارش(نام نرم افزار یجاد کننده) پایگاه داده - جهت اعتبار سنجی</param>
    ''' <param name="DbVerNum">شماره نگارش(نگارش نرم افزار یجاد کننده) پایگاه داده - جهت اعتبار سنجی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CheckConnetionString(ConnStr As String, DbVerName As String, DbVerNum As String) As Boolean
    Using myConn As New SqlConnection(ConnStr)
    Dim TSQL As String = ""
    TSQL = "SELECT DbVer FROM tblDbVer"
    Dim SqlRes = SqlFillTable(TSQL, Conn:=myConn)
    myConn.Dispose()
    If SqlRes Is Nothing Then Throw New Exception("عدم توانایی در دریافت اطلاعات")
    If SqlRes.Rows.Count = 0 Then
    Throw New Exception("اتصال به سرور انجام شد. ولی اطلاعاتی در یافت نگردید")
    End If
    Dim Ver = CStr(SqlRes.Rows(0)(0)).Split("|")
    If Ver.Count < 2 Then
    Throw New Exception("اتصال به سرور انجام شد. ولی اطلاعاتی در یافتی معتبر نمی باشد")
    End If
    If Ver(0) <> DbVerName Then
    Throw New Exception("اتصال به سرور انجام شد. ولی پایگاه داده مورد نظر متعلق به این نرم افزار نمی باشد")
    End If
    If Ver(1) <> DbVerNum Then
    Throw New Exception("اتصال به سرور انجام شد. ولی پایگاه داده مورد نظر متعلق به نگارش دیگری از این نرم افزار نمی باشد")
    End If
    End Using
    Return True
    End Function



    توضیح کد:

    در ابتدا یک Connection جهت اجرای دستورت ساخته می شود
    نکته:چون هنوز این رشته اتصال بررسی نشده و صحت آن معلوم نیست و همچنین به تایید نهایی کاربر نرسیده است ما نمی توانیم آن را به اتصال عمومی(GlobalConnection) نسب دهیم زیرا این کار کل نرم افزار را تحت تاثیر قرار می دهد و نه ما قصد این کار داریم و نه کار صحیحی می باشد!

    در خط بعد یک دستور TSQL که اطلاعات جدول DbVer را بدست خواهد آورد را ایجاد می کنیم

    سپس با استفاده از تابع SqlFillTable دستور را اجرا و نتیجه را به صورت یک DataTable دریافت می نماییم(این تابع نیز مورد بررسی قرار خواهد گرفت)
    توجه کنید ما علاوه بر دستور TSQL یک Connection نیز به این تابع ارسال می نماییم تا تابع در اجرای دستورات به جای اتصال عمومی از اتصال سفارشی ما استفاده نمایید(که امکانات این کار را نیز محیا کرده ایم)

    نکته:در این کد نیز پیغام خطا خود راهنمای کد هستند

    بعد از اجرای دستور چنانچه خطایی رخ نداده باشد به بررسی اطلاعات خواهیم پرداخت (برگشت مقدار Nothing نشان دهنده بروز خطا می باشد!)
    پس اگر مقدار Nothing برگشت داده نشده نتیجه می گیریم که اتصال به سرور انجام شده و ساختار پایگاه داده نیز با ساختار مورد نظر ما مطابقت دارد(دارای جدولی به نام DbVer می باشد!)

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

    نکته:ما در زمان ایجاد پایگاه داده یک رکورد به این جدول اضافه می نماییم تا با همان رکورد اعتبار سنجی های بعدی انجام شود
    این رکورد داری یک ستون است که مقدار آن توسط یک خط عمودی (|) به دوقسمت تقسیم می شود. قسمت اول نشانگر نام نگارش(نرم افزار ایجاد کننده) و قسمت دوم نگارش آن است(این مطالب در قسمت متغیر ها توضیح داده شد است)

    البته ما می توانستیم دو ستون جهت این کار ایجاد نماییم ولی با اینکار ما یک اعتبار سنجی هم انجام می دهیم که آیا اطلاعات با فرمت مختص به ما نوشته شده است یا نه

    اطلاعات دریافتی را جهت جدا سازی با | تقسیم می نماییم و اگر تقسیم انجام نشد نتیجه می گیریم که فرمت اطلاعات صحیح نبوده و پایگاه داده رد می شد!

    حالا با مقاسه دو قسمت با متغیر های خود نگارش پایگاه داده را بررسی و در صورت صحیح بود ن پایگاه داده و در نتیجه رشته اتصال را مورد قبول خواهیم نمود


    تابع SqlFillTable :

    همان طور که در قسمت توضیحات آن نیز قابل مشاهده است این تابع یک دستور TSQL که معمولا با دستور SELECT ایجاد می شود را دریافت و توسط آن پرس و جو را بر روی پایگاه داده اجرا و داخل یک شیئ DataTable قرار داده و آن را برگشت می دهد
    نکته:
    مشاهده می شود که بجز دستور TSQL باقی پارامتر ها به صورت اختیاری تعریف شده تا در صورت نیاز هر یک از اشیا دخیل در عملیات قابلیت سفارشی سازی داشته باشند

    نمونه ای از این سفارشی سازی را در همین ابتدای کار و در تابع بالا مشاهده نموده و به توانایی بسیار بالای این توابع و فایده های آنها پی بردید

    سفارشی سازی هم به این صورت اعمال می شود که اگر فراخوان اشیا را برای تابع ارسال نمایید از همان و در غیر این صورت یک نمونه جدید از آن جهت استفاده ایجاد می شود

    جهت کامل شدن عملیات از صفحه Properties پروژه Startup Form را با frmAppSplashتنظیم و Form1 را که در ابتدای ایجاد پروژه ایجاد شده بود حذف کنید!

    (در ادامه کار به بررسی ورود کاربران خواهیم پرداخت)
    آخرین ویرایش به وسیله فرید نجفلو : پنج شنبه 17 فروردین 1391 در 13:25 عصر

  18. #18
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ایجاد فرم اعتبار سنجی و ورود کاربر:

    بعد از دریافت رشته اتصال نوبت به اعتبار سنجی و ورود کاربر به برنامه می رسد

    توجه:

    اگر به دقت به عمق ماجرا دقت کنید متوجه می شوید که در واقع دو مرحله اعتبار سنجی کاربر داریم

    1-اعتبار سنجی در سطح سرور :
    این همان مرحله دریافت رشته اتصال بود به این صورت که اگر شخصی نام کاربری ، کلمه عبور و همچنین مجوزی در سرور نداشته باشد نخواهد توانست به سرور متصل شود و در نتیجه رشته اتصالی هم ایجاد نخواهد شد و در همان مرحله متوقف می شود
    با این تفاسیر مرحله دریافت اتصال نیز خود به نوعی اعتبار سنجی کاربر به حساب می آید

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

    پس ما در این مرحله و در این فرم ، اعتبار سنجی نوع دوم(نرم افزار یا پایگاه داده) را انجام خواهیم داد

    افزودن فرم:
    یک فرم جدید به نام frmLogin به پروژه اضافه نمایید
    بعد از افزودن کنترل ها(طبق پروژه نمونه) کد های زیر را به فرم اضافه نمایید:

    Public Class frmLogin
    #Region "متغیر ها"
    ''' <summary>
    '''رشته اتصال سفارشی جهت ارتباط با پایگاه داده
    ''' اگر توسط فراخوان ارسال نشود از رشته اتصال عمومی استفاده خواهد شد
    ''' </summary>
    ''' <remarks></remarks>
    Private CostumConnStr As String = ""
    ''' <summary>
    ''' تعداد دفعات ورود اطلاعات نادرست
    ''' </summary>
    ''' <remarks></remarks>
    Private TriedTimes As Integer = 0
    ''' <summary>
    ''' حداکثر مجاز دفعات ورود اطلاعات نادرست
    ''' </summary>
    ''' <remarks></remarks>
    Private Const MaxTryTime As Integer = 5
    #End Region
    #Region "توابع و متد ها"
    ''' <summary>
    ''' نمایش فرم و دریافت اطلاعات از کاربر
    ''' </summary>
    ''' <param name="ConnStr">رشته اتصال جهت بارگذاری کنترل </param>
    ''' <returns>برگشت نام کاربر</returns>
    ''' <remarks></remarks>
    Public Shadows Function ShowDialog(Optional ConnStr As String = "") As String
    Try
    CostumConnStr = ConnStr
    Me.DialogResult = Windows.Forms.DialogResult.Cancel
    MyBase.ShowDialog()
    If Me.DialogResult = Windows.Forms.DialogResult.OK Then
    Return txtUserName.Text
    Else
    Return ""
    End If
    Catch ex As Exception
    Return ""
    End Try
    End Function
    ''' <summary>
    ''' بررسی صحت اطلاعات ورودی توسط کاربر
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IsValidData() As Boolean
    Try
    Me.ErrorProvider1.Clear()
    If txtUserName.Text.Trim = "" Then
    ErrorProvider1.SetError(txtUserName, "نام کاربری وارد نشده است!")
    Throw New Exception("نام کاربری وارد نشده است")
    End If
    If txtPassword.Text.Trim = "" Then
    ErrorProvider1.SetError(txtPassword, "کلمه عبور وارد نشده است")
    Throw New Exception("کلمه عبور وارد نشده است")
    End If
    Return True
    Catch ex As Exception
    MsgBox("اطلاعات ورودی نا معتبر!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    Return False
    End Try
    End Function
    ''' <summary>
    ''' بررسی مشخصات و مجوز ورود کاربر
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function TestUser() As Boolean
    Try
    ErrorCache = ""
    If Not IsValidData() Then Return False
    If Not UserMgr.CheckUserForLogin(txtUserName.Text, txtPassword.Text, CostumeConnStr:=CostumConnStr) Then
    Throw New Exception("نام کاربری ، کلمه عبور یا مجوز معتبر نمی باشد")
    End If
    Return True
    Catch ex As Exception
    MsgBox("خطا در ورود" & vbNewLine & _
    ex.Message & vbNewLine & ErrorCache, _
    MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    TriedTimes += 1
    Return False
    End Try
    End Function
    #End Region
    #Region "روال رویداد ها"
    Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click
    Me.DialogResult = Windows.Forms.DialogResult.Cancel
    Me.Close()
    End Sub
    Private Sub btnOK_Click(sender As System.Object, e As System.EventArgs) Handles btnOK.Click
    If TestUser() Then
    Me.DialogResult = Windows.Forms.DialogResult.OK
    Me.Close()
    ElseIf TriedTimes >= MaxTryTime Then
    Me.DialogResult = Windows.Forms.DialogResult.Cancel
    Me.Close()
    End If
    End Sub
    #End Region

    End Class


    توضیح کد:
    تنها قسمتی که ممکن ایت نیز به توضیح داشته باشد تابع TestUser است:

    این تابع ابتدا مخزن خطا ها را خالی و سپس اقدام به بررسی مقادیر وردی می کند (که توضیحی هم نیاز ندارند همانند فرم انتخاب پایگاه داده می باشد)
    در ادامه اطلاعات را به تابع UserMgr.CheckUserForLogin فرستاده و تمام کار ها را به آن محول می کند (تمام متد ها و توابع استفاده شده به ترتیب کاربرد توضیح داده می شوند)
    نکته:باز تاکید می نماییم که به دلیل لزوم جدا سازی عملیات هر یک از لایه ها و با توجه به اینکه تابع UserMgr.CheckUserForLogin به طور مستقیم اقدام به ارتباط با پایگاه داده خواهد نمود اجازه حضور در لایه رابط کاربری(PL) نخواهد داشت و کلاس UserMgr نیز به رشد خود ادامه داده و به لایه میانی (BLL) کار با کاربران تبدیل خواهد شد!

    تابع UserMgr.CheckUserForLogin:

    همان طور که از نام تابع نیز قابل استنباط است این تابع در داخل کلاس UserMgr قرار دارد پس ابتدا باید کلاس مذکور ایجاد شود
    کلاس جدیدی به نام UserMgr به پوشه Calss\DB اضافه نمایید
    حال کد های زیر را نیز به کلاس اضافه نمایید:

        ''' <summary>
    ''' لیست کلیه مجوز های موجود - جهت دسترسی سریع و جلوگیری
    ''' از اشتباهات در هنگام برنامه نویسی
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum Premissions As Integer
    LoginToApp = 0

    End Enum


    Premissions یک نوع شمارشی می باشد و وظیفه آن نگه داری نام و کد کلیه مجوز هایی است که در نرم ام افزار موجود و قابل اختصاص به کاربران می باشد و پیش نیازی نیز جهت تابع CheckUserForLogin است

    دلایل وجودی Premissions :

    1-عدم اشتباه در تخصیص و بررسی مجوزات: به این صورت که زمانی که در کد کدنویسی قصد اختصاص یا کنترل مجوز به کاربر خواهیم داشت از اعضای این شمارش گر استفاده خواهیم نمود به عنوان مثال به جای استفاده از 0 برای کد مجوز ورود به نرم افزار از Premissions.LoginToApp استفاده و خود کاملا متوجه خواهیم بود که در حال اختصاص کدام مجوز به کاربر هستیم

    2-سهولت کد نویسی

    3-خوانایی بالا و دیباگ راحت تر

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

    نکته:افزایش ، کاهش و ویرایش مجوزات موجود فقط در زمان طراحی خواهد بود و این کار بعد از اتمام و عرضه نهایی و هنگام اجرا و استفاده از نرم افزار صورت نخواهد گرفت(در واقع در DesignTime خواهد بود نه RunTime)

    حال تابع CheckUserForLogin را به کلاس اضافه نمایید:


        ''' <summary>
    ''' بررسی صحت نام کاربری و کلمه عبور
    ''' </summary>
    ''' <param name="UserName">نام کاربری وارد شده</param>
    ''' <param name="PassWord">کلمه عبور وارد شده</param>
    ''' <param name="CostumeConnStr">رشته اتصال سفارشی - غیر از رشته اتصال عمومی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function CheckUserForLogin(ByVal UserName As String, _
    ByVal PassWord As String, _
    Optional ByVal CostumeConnStr As String = "") As Boolean
    UserName = UserName.Trim.ToLower
    Dim encrptPassword As String = Strings.Left(StringCoding(PassWord), 1000)
    Dim TSQL As String = "SELECT Password FROM tblUser WHERE LOWER(UserName) = " & _
    PrepStrToSql(UserName)
    Dim SqlRes As DataTable
    Using MyConn As New SqlConnection(CostumeConnStr)
    SqlRes = SqlFillTable(TSQL, Conn:=IIf(CostumeConnStr <> "", MyConn, Nothing))
    If SqlRes Is Nothing OrElse SqlRes.Rows.Count <= 0 Then
    Throw New Exception("نام کاربری یا کلمه عبور معتبر نمی باشد")
    End If
    If CStr(SqlRes.Rows(0).Item(0).ToString) <> encrptPassword Then
    Throw New Exception("نام کاربری یا کلمه عبور معتبر نمی باشد")
    End If
    TSQL = ""
    TSQL = "SELECT * FROM tblUserPremission WHERE LOWER(UserName) = '{0}' AND Premission = {1} "
    TSQL = String.Format(TSQL, UserName, CInt(Premissions.LoginToApp))
    SqlRes = Nothing
    SqlRes = SqlFillTable(TSQL, Conn:=IIf(CostumeConnStr <> "", MyConn, Nothing))
    If SqlRes Is Nothing OrElse SqlRes.Rows.Count <= 0 Then
    Throw New Exception("شما مجوز ورود را ندارید")
    End If
    MyConn.Dispose()
    End Using
    Return True
    End Function


    توضیح کد:

    این تابع دو وظیفه مهم بر عهده دارد:
    1-بررسی صحت نام کاربری و کلمه عبور وارد شده
    2-بررسی وجود مجوز ورود به نرم افزار(پایگاه داده) کاربر

    Dim encrptPassword As String = Strings.Left(StringCoding(PassWord), 1000)


    بدلیل اینکه قرار دادن کلمه عبور به همان صورت در پایگاه داده کار صحیحی از جهت اصول امنیتی نمی باشد ما کلمه عبور تمام کاربران را به صورت کدگذاری شده(توسط توسط تابع StringDecoding ) در پایگاه داده ذخیره می شود

    پس در این خط ما کلمه عبور دریافتی را به کدگذاری شده تبدیل و اقدام مقایسه آن با کلمه عبور پایگاه داده (که آن نیز کدگذاری شده) خواهیم نمود
    دلیل استفاده از 1000 کاراکتر اول (در صورت عبور از این اندازه) این است که چون حداکثر تعداد کاراکترهای مجاز فیلد Password در جدول tblUser را 1000 کارکتر قرار داده ایم پس در هنگام قرار دادن پسورد کاربر در داخل آن کلمه عبور کد گذاری و فرستاده شده بیش از 1000 کاراکتر نبوده است

    چون ما قصد بازگردانی کلمه عبور اصلی را نداریم و فقط مقادیر کد گذاری شده با هم مقایسه می شوند این کوتاه کردن رشته موجوب بروز مشکل مقایسه نخواهد شد(اگر کلمه عبور اصلی و دریافت شده برابر باشند هر دو به یک اندازه یعنی 1000 کارکتر بریده شده اند)

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

                SqlRes = SqlFillTable(TSQL, Conn:=IIf(CostumeConnStr <> "", MyConn, Nothing))


    و درواقع این قسمت:

    IIf(CostumeConnStr <> "", MyConn, Nothing)


    تابع IIf یک شرط تک خطی(InLine) می باشد و به این صورت عمل می کند که اگر شرط در پارامتر اول صحیح(True) باشد مقدار پارامتر دوم و در غیر این صورت مقدار پارامتر سوم برگشت داده خواهد شد

    دلیل استفاده:

    همان طور که ملاحظه می شود این تابع یک پارامتر اختیاری دارد که رشته اتصال پایگاه داده می باشد اگر این پارامتر ارسال شود تابع باید یک اتصال سفارشی ساخته و به تابع SqlFillTable ارسال نماید و در غیر این صورت نیاز به ارسال پارامتر نخواهد بود(مقدار پارامتر Nothing پیش فرض خواهد بود)

    حال ما یک اتصال سفارشی ساخته ایم (MyConn) ولی ممکن است از آن استفاده کنیم یا نکنیم و این بستگی به آن پارامتر اختیاری رشته اتصال دارد

    پس ما در این خط بررسی می نماییم که اگر پارامتر ارسال شده است(رشته خالی نخواهد بود) پارامتر اول یعنی اتصال سفارشی یا در غیر این صورت از Nothing (مقدار پیش فرض و نشانگر عدم ارسال پارامتر) را به عنوان مقدار Conn به تابع SqlFillTable فرستاده شود

    نکته: اگر خود بررسی نمایید و روش های دیگر را نیز امتحان کنید درخواهید یافت که این نصف خط کد کار چنین خط کد را انجام داده است

    نکته جالب: نکته جالبی که در این بین وجود دارد این است که تا این مرحله تمام ارتباطات ما با پایگاه داده با روش مستقیم TSQL و همچنین در حالات استثنا بوده است که امید واریم این امر موجب سردرگمی و سخت شدن مراحل ابتدایی کار نشده باشد

    در ادامه کار و بعد از شناسایی کاربر و تایید کلمه عبور اقدام به بررسی مجوز ورود می شود

    نکنه1: تا این نقطه ما تنها نیاز به یک مجوز یعنی مجوز ورود داریم که هم به پایگاه داده و هم به نوع شمارشی Premissions افزوده شده است

    نکته 2:چون در اولین اجرای نرم افزار هنوز کاربری وارد برنامه نشده و در نتیجه هیچ کاربری هم ایجاد نشده جهت اینکه حداقل یک کاربر جهت ورود وجود داشته باشد اقدام به افزودن دستی یک کاربر به پایگاه داده به عنوان کاربر اولیه و پیش فرض می نماییم که این کاربر داری تمام مجوزات موجود است تا بتواند به عنوان مدیر اولیه به تمام قیمت های نرم افزار دسترسی و تنظیمات اولیه را انجام دهد(همانند کاربر Sa در SQL Server و admin در اکسس)

    نکته 3: شما باید به استفاده کننده از نرم افزار هشدار بدهید که این کاربر در اولین فرصت باید حذف یا کلمه عبور آن تغییر یابد

    نکته 4: نام کاربری پیش فرض و همچنین کلمه عبور آن باید به اطلاع کاربر نهایی برسد (به عنوان مثال در راهنمای نرم افزار ، جلد روی CD ، صفحه دانلود نرم افزار و ...) همان طور که ما در نکته بعدی به شما اطلاع می دیم

    نکته 5: نام کاربری پیشفرض ما admin و کلمه عبور آن 1 (عدد یک) می باشد


    توابع کدگذاری:

    جهت مسائل امنیتی ما نیاز خواهیم داشت تا بعضی اطلاعات خود را به صورت رمزنگاری شده ذخیره و در هنگام استفاده آنها را رمز گشایی کنیم
    مواردی از این قبیل همین کلمه عبور کاربر و رشته اتصالی خواهد بود که اقدام به ذخیره و بازیابی آن در اجرا های بعدی خواهیم نمود می باشند

    جهت رسیدن به منظور دو تابع را در کلاس Publics به صورت زیر اصلاح کنید:

        ''' <summary>
    ''' رمز گذاری یک رشته متنی
    ''' </summary>
    ''' <param name="InputStr">رشته جهت کدگذاری</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function StringCoding(InputStr As String) As String
    Try
    Dim Key As String = "https://barnamenevis.org/member.php?243869-Farid.N"
    Dim DES As New System.Security.Cryptography.TripleDESCryptoServic eProvider
    Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvi der
    DES.Key = MD5.ComputeHash(System.Text.UTF8Encoding.UTF8.GetB ytes(Key))
    DES.Mode = System.Security.Cryptography.CipherMode.ECB
    Dim Buffer As Byte() = System.Text.UTF8Encoding.UTF8.GetBytes(InputStr)
    Return Convert.ToBase64String(DES.CreateEncryptor().Trans formFinalBlock(Buffer, 0, Buffer.Length))
    Catch ex As Exception
    Return InputStr
    End Try
    End Function
    ''' <summary>
    ''' رمزگشایی یک رشته کد شده
    ''' </summary>
    ''' <param name="InputStr">رشته کد شده</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function StringDecoding(InputStr As String) As String
    Try
    Dim Key As String = "https://barnamenevis.org/member.php?243869-Farid.N"
    Dim DES As New System.Security.Cryptography.TripleDESCryptoServic eProvider
    Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvi der
    DES.Key = MD5.ComputeHash(System.Text.UTF8Encoding.UTF8.GetB ytes(Key))
    DES.Mode = System.Security.Cryptography.CipherMode.ECB
    Dim Buffer As Byte() = Convert.FromBase64String(InputStr)
    Return System.Text.UTF8Encoding.UTF8.GetString(DES.Create Decryptor().TransformFinalBlock(Buffer, 0, Buffer.Length))
    Catch ex As Exception
    Return InputStr
    End Try
    End Function


    نکته :

    ما از توضیح این دو تابع به دو دلیل صرف نظر نموده و به این اکتفا می کنیم که تابع اول یک رشته دریافت و آن را با یک کلید رمزنگاری و تابع دوم رشته ای را که توسط تابع اول رمزنگاری شده ، رمزگشایی می کند:

    1-عملکرد و توضیح این توابع خارج از بحث است
    2-این واقیت وجود داد که هر نرم افزار باید الگوریتم رمزنگاری خود را داشته باشد و این به عهده خود شماست که آن را ایجاد نمایید

    اصلاح متد Loader:

    حال که فرم ورود کاربران آماده شد نوبت به بکارگیری از آن می رسد و اولین نقطه ای که باید مورد استفاده قرار گیرد متد Loader است

    پس متد را به صورت زیر تغییر دهید:

        ''' <summary>
    ''' این متد اجرای برنامه را از صفحه نخست دریافت و ادامه کارها را بر عهده می گیرد
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub Loader()
    Try
    'انجام کار های پیش نیاز
    InitAdapters()
    'فراخوانی فرم دریافت اطلاعات پایگاه داده
    Dim frmDb As New frmDatabase
    GetConnStr:
    Dim ConnStr As String = frmDb.ShowDialog(ConnStr)
    If ConnStr = "" Then
    End
    End If
    'فراخوانی فرم ورود کاربران
    Dim frmlgn As New frmLogin
    Dim User As String = frmlgn.ShowDialog(ConnStr:=ConnStr)
    frmlgn.Dispose()
    If User = "" Then
    GoTo GetConnStr 'try agin
    End If
    CurrentUserName = User
    GlobalConnectionString.ConnectionString = ConnStr
    GlobalConnection.ConnectionString = ConnStr
    frmDb.Dispose()
    'فراخوانی فرم اصلی
    FrmMain.Show()
    'انجام کار های مورد نیاز بعدی
    Catch ex As Exception
    MsgBox("خطا در بارگذاری برنامه!" & vbNewLine & ex.Message, _
    MsgBoxStyle.Critical + MsgBoxStyle.MsgBoxRtlReading + MsgBoxStyle.MsgBoxRight, _
    "خطای جدی")
    AddError(ex.Message)
    End
    End Try
    End Sub


    همنطور که مشاهده می شود ابتدا اقدام به دریافت کاربر تایید شده از فرم ورود کاربران نموده در صورتی که کاربر انصراف داده یا تعداد مجاز اشتباهات وی از حد مجاز فراتر رفته باشد وی را دوباره به صفحه انتخاب پایگاه داده راهنمایی می کنم تا در صورت لزوم پایگاه داده خود را مجددا معرفی و فرصتی جهت تلاش مجدد برای ورود داشته باشد
    در صورتی که کاربر نام کاربری و کلمه عبور صحیح و مجوز ورود نیز اعطا شده باشد فرم ورود کاربر، نام کاربری را برای ما ارسال خواهد کرد
    و متد Loader هم نام کاربر فعال شده را جهت استفاده های بعدی در یک متغیرر عمومی ذخیره می کند
    سپس نوبت به مهترین نقطه یعنی تنظیم رشته اتصال عمومی رسیده و بعد از این عمل کاربر به فرم اصلی هدایت می شود

    درنهایت این متد بعد از اتمام وظیفه خطیر خود عملیات را به پایان می رساند و فرم Splash نیز که تا این لحظه منتظر بود وارد عمل شده و فرم خود را که مخفی کرده بود به طور کامل بسته و از بین می برد(البته یک کار دیگر باقی مانده است که باید انجام شود و آن ذخیره رشته اتصال برای استفاده در اجرا های بهدی می باشد که در مطلب بعدی اضافه خواهد شد)

    ایجاد فرم اصلی:

    همانطور که ملاحظه نمودید در نهایت کاربر به یک فرم اصلی که معرف نرم افزار ما می باشد هدایت می گردد
    پس ما باید این فرم را به برنامه اضافه نماییم
    پنجره Add New Item را باز و یک فرم MDIParent با نام FrmMain را به پوشه Form\App اضافه نمایید
    حال تمام کنترل ها و کدهای این فرم را حذف نمایید(به مرور خود این فرم را تکمیل خواهیم نمود)

    در نهایت پروژه خود را ذخیره نمایید

    نکته مهم:

    همانطور که قبلا نیز اشاره شد دو نوع اعتبار سنجی (سطح سرور و سطح پایگاه داده) با هم یک امنیت قدرتمند ایجاد می کنند
    اما چنانچه سرور در حالت MixedMode نبوده و از اعتبار سنجی ویندوزی استفاده نماید یکی از مراحل اعتبار سنجی از بین می رود که به نوبه خود اعتبار سنجی سطح پایگاه داده را نیز به خطر می اندازد
    به این صورت که در صورت نبود امنیت برای سرور هر کسی می تواند با یک ابزار ساده کار با پایگاه داده وارد سرور شده و جدول های مربوط به کاربران را به راحتی دست کاری نموده و به خود مجوزات در سطح مدیر را اضافه نمایید!!!

    پس همیشه سرور خود را با حالت MixedMode و نام کاربری و کلمه عبور مستحکم ، امن نگاه دارید

  19. #19
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ذخیره رشته اتصال:

    همانطور که می دانید این کار صحیحی نیست که ما در هر اجرا از برنامه اقدام به دریافت تمام مشخصات سرور پایگاه داده از کاربر نماییم در حالی که وی در اجرای قبلی آنها را ارائه نموده بود
    پس ما می توانیم رشته اتصالی را که از کاربر دریافت نموده و صحت آن نیز بررسی شده است را در مکانی ذخیره و در اجرای بعدی آن را بازیابی و خود اقدام به تنظیم مقادیر در کنترل های فرم "انتخاب پایگاه داده" نماییم که ممکن است با این کار فقط نیاز به تایید آن توسط کاربر داشته باشیم(کلیک یک دکمه و تمام!)

    رشته اتصال را کجا ذخیره کنیم؟
    مکان های متعددی را جهت این کار پیش رو دارید مثلا ریجستری ، یک فایل TXT ، یک فایل XML ، یک فایل INI و...

    ولی گزینه بهتری پیشرو دارید و آن استفاده از تنظیمات یا Settings برنامه است که قدرتی فوق العاده و کاربردی راحت دارد . ما نیز از همین امکانات بهره خواهیم برد

    برای ادامه ازSolution Explorer بر روی گره (نام) پروژه خود کلیک راست و گزینه Properties را انتخاب نمایید
    از پنجره باز شده برگ Settings را باز نمایید
    حال از گرید سمت راست در ستون Name اولین سطر خالی مقدار LastConnectionString را وارد نمایید
    در ستون Type گزینه String و در ستون Scope گزینه User را انتخاب نمایید . ستون آخر را نیز بدون تغییر رها کنید

    پروژه خود را ذخیره کنید
    با این کار شما یک محل برای ذخیره یک رشته ایجاد نمودید

    رشته اتصال را چگونه ذخیره کنیم؟

    بهترین روش برای این کار داشتن دو تابع جداگانه برای ذخیره و بازیابی رشته اتصال می باشئد
    پس کد های زیر را به کلاس Publics اضافه نمایید

     ''' <summary>
    ''' ذخیره رشته اتصال در تنظیمات نرم افزار
    ''' </summary>
    ''' <param name="ConnStr"></param>
    ''' <remarks></remarks>
    Public Shared Sub SaveLastConnectionString(ConnStr As String)
    Try
    Dim tmpConnStrBldr As New SqlConnectionStringBuilder(ConnStr)
    tmpConnStrBldr.Password = ""
    My.Settings.LastConnectionString = StringCoding(tmpConnStrBldr.ConnectionString)
    My.Settings.Save()
    Catch ex As Exception
    End Try
    End Sub
    ''' <summary>
    ''' بازیابی رشته اتصال ذخیره شده در اجرای قبل
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetLastConnectionString() As String
    Try
    Dim ConnStr As String = My.Settings.LastConnectionString
    If ConnStr = "" Then Return ""
    Return StringDecoding(ConnStr)
    Catch ex As Exception
    Return ""
    End Try
    End Function


    توضیح تابع SaveLastConnectionString یک رشته اتصال را دریافت و آن را رمزگذاری کرده و در Settings برنامه و محلی که ما قبلا ایجاد نمودیم ذخیره می کند

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

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

    رشته اتصال چه موقع ذخیره و بازیابی می شود؟

    هدف ما از ذخیره سازی رشته اتصال راحتی کاربر نهایی می باشد و ما چیزی را ذخیره می کنیم که وی به ما داده است
    با توجه به اینکه ما رشته اتصال را در داخل متد Loader دریافت و در همان جا بررسی و مورد تایید قرار می دهیم بهترین مکان برای عملیات ذخیره می باشد
    همچنین ما در داخل همین متد است که فرم "انتخاب پایگاه داده" را فراخوانی و رشته اتصالی به آن ارسال می نماییم با این تفاسیر بازیابی رشته اتصال هم در همین متد صورت می پذیرد
    هرچند بعد ها ممکن است در مکان (های) دیگری نیز اقدام به این کار نماییم ولی اولین نقطه و مهمترین شان همین متد می باشد

    پس متد Loder را به شکل زیر اصلاح نمایید:

     ''' <summary>
    ''' این متد اجرای برنامه را از صفحه نخست دریافت و ادامه کارها را بر عهده می گیرد
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub Loader()
    Try
    'انجام کار های پیش نیاز
    InitAdapters()
    'فراخوانی فرم دریافت اطلاعات پایگاه داده
    Dim ConnStr As String = GetLastConnectionString()
    Dim frmDb As New frmDatabase
    GetConnStr:
    ConnStr = frmDb.ShowDialog(ConnStr)
    If ConnStr = "" Then
    End
    End If
    'فراخوانی فرم ورود کاربران
    Dim frmlgn As New frmLogin
    Dim User As String = frmlgn.ShowDialog(ConnStr:=ConnStr)
    frmlgn.Dispose()
    If User = "" Then
    GoTo GetConnStr 'try agin
    End If
    CurrentUserName = User
    GlobalConnectionString.ConnectionString = ConnStr
    GlobalConnection.ConnectionString = ConnStr
    SaveLastConnectionString(ConnStr)
    frmDb.Dispose()
    'فراخوانی فرم اصلی
    FrmMain.Show()
    'انجام کار های مورد نیاز بعدی
    Catch ex As Exception
    MsgBox("خطا در بارگذاری برنامه!" & vbNewLine & ex.Message, _
    MsgBoxStyle.Critical + MsgBoxStyle.MsgBoxRtlReading + MsgBoxStyle.MsgBoxRight, _
    "خطای جدی")
    AddError(ex.Message)
    End
    End Try
    End Sub


    کلا دو خط کد اضافه شد که توضیحی نیاز ندارد!

    (انشا ا... از مطالب بعدی کار با پایگاه داده به صورت جدیتر شروع خواهد شد)

  20. #20
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    مدیریت کاربران بخش اول:ایجاد،ویرایش،حذف کاربران لایه رابط کابری(PL):

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

    همچنین توجه داشته باشید کد ها در این قسمت پیچیده تر از مراحل قبلی خواهد بود پس به کد ها و توضیحات با دقت بیشتری توجه کرده و سعی در مرور چندباره کدهای مبهم نمایید. ولی با این حال رفته رفته متوجه خواهد شد روش های این قسمت بسیار راحتر ، کارامدتر و امن تر از روش دیگر یعنی استفاده مستقیم از دستورات TSQL خواهد بود
    پس چنانچه در درک عملکرد بعضی قسمت ها با مشکل مواجه شدید نا امید نشوید و بدانید که آغاز هر کاری مشکل جلوه می کند ولی پس از یادگیری از آن لذت خواهید برد

    همانطور که دانستید ما از لایه بندی استفاده خواهیم نمود پس هر لایه را به صورت جداگانه مورد بررسی قرار خواهیم داد

    لایه رابط کاربری (PL)

    ایجاد فرم لیست کاربران موجود:

    کد های موجود در این فرم:

    (به خاطر دارید که قرار شده است دیگر در مورد طراحی رابط کاربری توضیحی داده نشود)

    Public Class frmUserList
    #Region "توابع و متد ها"
    ''' <summary>
    ''' دریافت لیست کاربران و نمایش آن به کاربر
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub LoadList()
    Try
    Me.dgvUserList.DataSource = Nothing
    Me.dgvUserList.DataSource = UserMgr.GetUsersDetailList
    Me.dgvUserList.AutoResizeColumns(DataGridViewAutoS izeColumnsMode.AllCells)
    Me.dgvUserList.Columns(dgvUserList.ColumnCount - 1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
    Catch ex As Exception
    End Try
    End Sub
    ''' <summary>
    ''' ایجاد کاربر جدید
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub AddNewUser()
    Try
    Dim MyfrmUsr As New frmUserAddEdit
    Dim res = MyfrmUsr.ShowDialog()
    If res Then LoadList()
    Catch ex As Exception
    MsgBox("عدم توانایی در انجام عملیات!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    End Try
    End Sub
    ''' <summary>
    ''' ویرایش کاربر انتخاب شده
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub EditUser()
    Try
    If dgvUserList.SelectedRows.Count = 0 Then Exit Try
    Dim SelecteUserName As String = dgvUserList.SelectedRows(0).Cells("نام کاربری").Value
    Dim MyfrmUsr As New frmUserAddEdit
    Dim res = MyfrmUsr.ShowDialog(SelecteUserName)
    If res Then LoadList()
    Catch ex As Exception
    MsgBox("عدم توانایی در انجام عملیات!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    End Try
    End Sub
    ''' <summary>
    ''' حذف کاربر انتخاب شده
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub DeleteUser()
    Try
    If dgvUserList.SelectedRows.Count = 0 Then Exit Try
    Dim SelecteUserName As String = dgvUserList.SelectedRows(0).Cells("نام کاربری").Value

    If MsgBox("آیا برای حذف این کاربر اطمینان دارید؟" & vbNewLine & _
    SelecteUserName, MsgBoxStyle.YesNo + _
    MsgBoxStyle.DefaultButton2 + MsgBoxStyle.Question + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا") <> MsgBoxResult.Yes Then
    Exit Try
    End If

    If UserMgr.DeleteUser(SelecteUserName) Then
    LoadList()
    End If
    Catch ex As Exception
    MsgBox("عدم توانایی در انجام عملیات!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    End Try
    End Sub
    #End Region
    #Region "روال رویدادها"
    Private Sub frmUserList_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    LoadList()
    End Sub
    Private Sub tsbExit_Click(sender As System.Object, e As System.EventArgs) Handles tsbExit.Click
    Me.Close()
    End Sub
    Private Sub tsbNewUser_Click(sender As System.Object, e As System.EventArgs) Handles tsbNewUser.Click
    AddNewUser()
    End Sub
    Private Sub tsbEditUser_Click(sender As System.Object, e As System.EventArgs) Handles tsbEditUser.Click
    EditUser()
    End Sub
    Private Sub tsbDeleteUser_Click(sender As System.Object, e As System.EventArgs) Handles tsbDeleteUser.Click
    DeleteUser()
    End Sub
    #End Region
    End Class


    نکته:

    اگر یک نگاه سطحی هم به کد های این فرم (و فرم های بعدی) انداخته شود دریافته می شود با آنکه این فرم ها و وظایفشان کاملا درگیر با پایگاه داده است ولی هیچ اثری از کار با پایگاه داده دیدی نمی شود!(زیرا این لایه رابط کاربری (PL) می باشد)
    تنها چیزی که دیده می شود این است که چند تابع با پارمتر صدا زده شده و نتیجه آن (که معمولایک نوع ساده یعنی بولین است) مورد برسی قرار می گیرد و فرم به هیچ وجه اطلاع ندارد در پشت پرده چه اتفاق های افتاده و اطلاعات از کجا آمده و کدام نوع پایگاه داده یا منبعی مورد استفاده قرار می گیرد. ما این نوع از کد نویسی را با استفاده از برنامه نویسی لایه ای انجام می دهیم
    جالب تر اینکه آن تابعی که ما آن را فرخوانی می کنیم در بیشتر اوقات خودش هم نخواهد فهمید اطلاعات از کدام منبع آمده است(این تابع خود در لایه میانی (BLL) قرار داشته و ارتباط مستقیم در لایه دسترسی به داده ها (DAL) انجام می شود)

    توضیح کد:

    تابع LoadList:

    این تابع وظیفه دریافت لیست کاربران و بارگذاری آن در یک کنترل DataGridView موجود در فرم جهت نمایش را دارد
    همانطور که می بیند ما نتیجه یک تابع را بارگذاری می کنیم یعنی عملیات کار با پایگاه داده که هیچ حتی به نوع برگشتی هم توجهی نداریم!
    (طبق روال گذشته هر تابع مورد استفاده در ادامه و در مکان خود توضیح داده می شود)

    تابع AddNewUser:

    این تابع ابتدا فرم frmUserAddEdit را فراخوانی کرده و عملیات ایجاد کاربر را به آن محول می نماید سپس باتوجه به نتیجه برگشتی درصورتی که کاربر با موفقیت ایجاد شده باشد(True) اقدام به تازه سازی لیست کاربران جهت نمایش تغییرات ایجاد شده در رابط کاربری می نماید!

    تابع EditUser:

    این تابع ابتدا بررسی می کند که کاربری انتخاب شده است یا نه و در صورت انتخاب اقدام به استخراج نام کاربری از کنترل dgvUserList می نماید
    همان طور که می بیند ما از نام فیلد استفاده ننموده ایم و فقط چیزی را که می بینیم (متن سرستون) دریافت می کنیم (نوشته ایم "نام کاربر" نه نام فیلد یعنی "UserName")
    سپس نام کاربر را به فرم frmUserAddEdit ارسال می نماید تا عملیات ویرایش را انجام و نتیجه را اعلام کند

    تابع DeleteUser:

    این عملیات داری قوانین بیشتری خواهد بود (حتی بعدها خواهیم دید که این قوانین فعلی افزایش خواهند یافت و محاسبات پیچیده ای انجام خواهد شد)
    البته بیشتر این قوانین در لایه میانی اعمال خواهد شد.

    قوانین:

    1-کاربر باید یک مورد را در لیست انتخاب کرده باشد
    2-کاربر باید عملیات حذف را تایید نماید

    بعد از گذراندن این قوانین اقدام به حذف کاربر با فراخوانی تابع آن از لایه BLL خواهیم نمود و بقیه قوانیین در آنجا ارزیابی خواهند شد

    خوب دید فرمی که باید بسیار پیچیده می بود خیلی ساده نوشته شده است و ممکن است عملیاتی که این فرم قرار است انجام دهد نسبت به کد های موجود عجیب جلوه کند(مخصوصا اگر از آن دسته افرادی باشید که همه کار ها را در داخل فرم انجام می دهند!)

    ما این را مدیون دو چیز هستیم:

    1-برنامه نویسی لایه ای
    2-تقسیم وظایف(تجزیه کار های بزرگ به قسمت های کوچک تر)

    فرم ایجاد و یرایش کابران:

    این یک فرم کوچک (از نظر ابعاد و بزرگ از نظر عملکرد) است که دو وظیفه بر عهده دارد:

    1-ایجاد یک کاربر جدید
    2-ویرایش و اصلاح یک کاربر موجود

    کد های فرم:

    Public Class frmUserAddEdit
    #Region "متغیر ها"
    ''' <summary>
    ''' نشانگر انصراف کاربر از ادامه یا انجام موفقیت آمیز
    ''' </summary>
    ''' <remarks></remarks>
    Private Canceled As Boolean = True
    ''' <summary>
    ''' نشانگر این که فرم جهت ویرایش یک کاربر موجود باز شده است یا ایجاد کاربر جدید
    ''' </summary>
    ''' <remarks></remarks>
    Private EditMode As Boolean = False
    #End Region
    #Region "توابع و متد ها"
    ''' <summary>
    ''' نمایش فرم و دریافت اطلاعات از کاربر
    ''' </summary>
    ''' <param name="UserNameToEdit">نام کاربری جهت ویرایش</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shadows Function ShowDialog(Optional UserNameToEdit As String = "")
    Try
    EditMode = UserNameToEdit <> ""
    If EditMode Then
    txtUserName.ReadOnly = True
    LoadDataForEdit(UserNameToEdit)
    End If
    MyBase.ShowDialog()
    If Canceled Then
    Return False
    Else
    Return True
    End If
    Catch ex As Exception
    MsgBox(ex.Message)
    Return False
    End Try
    End Function
    ''' <summary>
    ''' دریافت اطلاعات کاربر موجود و وارد کردن آنها در داخل کنترل هل جهت ویرایش
    ''' </summary>
    ''' <param name="UserName">نام کاربری جهت ویرایش</param>
    ''' <remarks></remarks>
    Private Sub LoadDataForEdit(UserName As String)
    Dim UserDitail = UserMgr.GetUserDetail(UserName)
    If UserDitail Is Nothing Then
    Throw New Exception("کاربر وجود ندارد!")
    End If
    txtUserName.Text = UserDitail.UserName
    txtPassword.Text = "" 'Password Not Loaded For Security Reasons
    txtConfirmPassword.Text = "" 'Password Not Loaded For Security Reasons
    txtFirstName.Text = UserDitail.FirstName
    txtLastName.Text = UserDitail.LastName
    End Sub
    ''' <summary>
    ''' بررسی صحت اطلاعات ورودی توسط کاربر
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IsValidData() As Boolean
    Try
    Me.ErrorProvider1.Clear()
    If txtUserName.Text.Trim = "" Then
    ErrorProvider1.SetError(txtUserName, "نام کاربری وارد نشده است!")
    Throw New Exception("نام کاربری وارد نشده است")
    End If
    If Not EditMode AndAlso txtPassword.Text.Trim = "" Then
    ErrorProvider1.SetError(txtPassword, "کلمه عبور وارد نشده است")
    Throw New Exception("کلمه عبور وارد نشده است")
    End If
    If txtPassword.Text <> txtConfirmPassword.Text Then
    ErrorProvider1.SetError(txtConfirmPassword, "تایید کلمه عبور با کلمه غبور مطابقت ندارد")
    Throw New Exception("تایید کلمه عبور با کلمه عبور مطابقت ندارد")
    End If
    If txtFirstName.Text.Trim = "" Then
    ErrorProvider1.SetError(txtFirstName, "نام وارد نشده است!")
    Throw New Exception("نام وارد نشده است")
    End If

    If txtLastName.Text.Trim = "" Then
    ErrorProvider1.SetError(txtLastName, "نام خانوادگی وارد نشده است!")
    Throw New Exception("نام خانوادگی وارد نشده است!")
    End If
    Return True
    Catch ex As Exception
    MsgBox("اطلاعات ورودی نا معتبر!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    Return False
    End Try
    End Function
    ''' <summary>
    ''' انجام عملیات ایجاد کاربر جدید یا ویرایش کاربر موجود
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>نوع عملیات بستگی به نحوه فراخوانی فرم دارد</remarks>
    Private Function Add_Edit() As Boolean
    Try
    If Not IsValidData() Then Return False
    If EditMode Then
    Dim Res = UserMgr.EditUser(txtUserName.Text, txtPassword.Text, txtFirstName.Text, txtLastName.Text)
    Return Res
    Else
    Dim Res = UserMgr.AddNewUser(txtUserName.Text, txtPassword.Text, txtFirstName.Text, txtLastName.Text)
    Return Res
    End If
    Return False
    Catch ex As Exception
    MsgBox("عدم توانایی در انجام عملیات!" & vbNewLine & _
    ex.Message, MsgBoxStyle.Exclamation + _
    MsgBoxStyle.MsgBoxRtlReading + _
    MsgBoxStyle.MsgBoxRight, "خطا")
    Return False
    End Try
    End Function
    #End Region
    #Region "روال رویداد ها"
    Private Sub btnOk_Click(sender As System.Object, e As System.EventArgs) Handles btnOk.Click
    If Add_Edit() Then
    Canceled = False
    Me.Close()
    End If
    End Sub
    Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click
    Me.Close()
    End Sub
    #End Region
    End Class


    طبق روال گذشته باید فهمیده باشید کدام قسمت از کد فرم قبل از همه توضیح داده خواهد شد!

    متغیر ها:

    Canceled:

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

    EditMode:
    گفتیم که این فرم دو وظیفه ایجاد کاربر و ویریش کاربر را بر عهده دارد که هر کدام نیازمند یک سری عملیات و بررسی شریط خواص خود هستند پس با تنظیم این متغیر سایر کد های فرم را از نوع عملیاتی که قرار است انجام شود(کاربر جدید یا ویرایش کاربر موجود ) با خبر ساخته و آنها نیز بر طبق آن عملیات آن نوع را انجام خواهند داد

    تابع ShowDialog:

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

    اولین خط:

     EditMode = UserNameToEdit <> ""


    این خط اقدام به تنظیم نوع فراخوانی ( یعنی قصد فراخوان از باز کردن این فرم) را تنظیم می کند
    همان طور که می دانید چنانچه دو شیئ با عملوندهای مقایسه ای ( = ،> ،< ،<> ،>=، <=) مقایسه شوند یکی از دو نتیجه True (برابر بودن) و False (نابرابر بودن) را برگشت خواهند داد
    پس در این کد چنانچه پارامتر UserNameToEdit برای فرم ارسال شده باشد می توان نتیجه گرفت که قصد از فراخوانی ویرایش یک کاربر موجود است و در غیر این صورت عملیات ایجاد کاربر جدید مورد درخواست می باشد
    در نتیجه در خط بالا اگر UserNameToEdit خالی نباشد حالت ویرایش فعال خواهد شد

    در خطوط بعدی چنانچه در حالت ویرایش باشیم نام کاربری را فقط خواندنی می کنیم زیرا نام کاربری غیر قابل ویریش است(به یاد دارید که کلید جدول بود!)
    سپس با استفاده از تابع LoadDataForEdit اطلاعات کاربر در فرم بارگذلری می شود
    در ادامه طبق روال فرم به نمایش در آمده و تابع منتظر کاربر و بسته شدن فرم می ماند

    متد LoadDataForEdit:

    این متد وظیفه دارد اطلاعات کاربر را دریافت و در کنترل ها قرار دهد تا در صورت لزوم ویرایش شوند

    توجه کنید که به دلایل امنیتی به هیچ وجه نباید کلمه عبور را بار گذری کرد و اصلا نیازی به این کار هم نیست چون در صورت بارگذاری هم قابل نمایش نمی باشد(به صورت ستاره دیده می شود!)

    تابع IsValidData:

    این تابع هم وظیف بررسی صحت اطلاعات وارد شده رد دارد که خود کد نیز گویای عملکرد می باشد
    فقط یک نکته وجودارد که در حالت ویرایش می توان کلمه عبور را خالی گذاشت زیرا ممکن است کاربر قصد تعویض آن را نداشته باشد.یکی از دلایل آن این می تواند باشد که کاربر (مدیر سیستم)در حال ویرایش مشخصات کاربر دیگری می باشد و تعویض کلمه عبور می تواند از ورود کاربر جلوگیری به عمل آورد در حالی که هدف فقط ویرایش مشخصات بود!

    تابع Add_Edit:

    این تابع با چند خط کد خود انجام کل عملیات اصلی بر عهده دارد!(باز هم لایه بندی)

    در قدم اول تابع اقدام به بررسی صحت اطلاعات می کند

    سپس به برسی نوع عملیات پرداخته تابع مناسب از لایه میانی(BLL) را پارامتر دهی کرده و فرخوانی می کند.(همین و تمام !)

    اصلاح فرم اصلی:

    تنها کاری که در این لایه باقی مانده است ایجاد راهی برای دسترسی به (باز کردن) پنجره لیست کابران است
    چون کار در این قسمت به جز یک کنترل منو و چند خط کد چیز دیگری وجود ندارد توضیح بیشتری نیز احساس نمی شود
    آخرین ویرایش به وسیله فرید نجفلو : جمعه 18 فروردین 1391 در 20:01 عصر

  21. #21
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    مدیریت کاربران بخش دوم:ایجاد،ویرایش،حذف کاربران لایه میانی و لایه دسترسی به داده(DAL,BLL):



    خوب کم کم به نقاط جالب نزدیک می شویم


    تا به حال( در قسمت رابط کاربری) برای هر کاری یک تابع مجهول الهویه ای را صدا زده و کار را به آن واگذار می کردیم که در این قسمت قصد معرفی آنها را داریم
    پس توابع مورد نظر این بخش را به ترتیب نیاز نه به ترتیب معرفی شده در قسمت قبلی مورد بررسی قرار می دهیم

    تمام توابع زیر در کلاس UserMgr قرار خواهند گرفت:

    تابع GetUsersDetailList:

     ''' <summary>
    ''' لیست کاربرن موجود
    ''' آماده شده جهت نمایش به کاربر
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetUsersDetailList() As tblUserDetailDataTable
    Dim Result As tblUserDetailDataTable
    Result = AdpMgr.tblUserDetailTableAdapter.GetData
    Result.UserNameColumn.ColumnName = "نام کاربری"
    Result.FirstNameColumn.ColumnName = "نام"
    Result.LastNameColumn.ColumnName = "نام خانوادگی"
    Result.CreateDateColumn.ColumnName = "تاریخ ایجاد"
    Result.LastLoginColumn.ColumnName = "تاریخ آخرین ورود به سیستم"
    Return Result
    End Function


    همانطور که می بینید تابع از دو شیئ (یا کلاس) tblUserDetailDataTable و AdpMgr.tblUserDetailTableAdapter استفاده کرده است

    این دو کلاس چیستند و از کجا آمده اند؟

    بله هچ کدام از این دو را ما به صورت صریح ایجاد نکرده ایم و کدی برای آنها ننوشته ایم اما آنها نتیجه یکی از کارهای خود ما می باشند
    به یاد می آورید که ما یک Dataset به پروژه خود اضافه کردیم و بعد جداول پایگاه داده را درون آن اضافه نمودیم؟
    درست در همان زمانی که ما جداول را به داخل Dataset انداختیم در پشت پرده و به صورت خودکار کد های فراوانی ایجاد شد (تا به حال برای پروژه خودمان بیش از 10.000 خط کد!) در بین این کدها برای هر جدول سه کلاس بسیار مهم و پر کاربرد اضافه می شود که عبارتند از:

    DataRow
    DataTable
    TableAdapter

    که نام هر یک عبارت است از نام جدول باضافه نام نوع کلاس (برای مثال tblUserDetailDataRow)
    حال ببینیم هر کدام چه وظیفه ای بر عهده دارند:


    DataRow:

    هر نمونه از این شیئ وظیفه نگه داری یک رکورد از اطلاعات جدول مربوط به خود را دارد و برای هر فیلد از جدول نیز یک خاصیت برای آن تعیین شده است که به شما امکان می دهد به صورت شیئ گرا(بدون نوشتن نام فیلد) به صورت مستقیم مقدار آن فیلد را بدست آورد برای مثال وقتی یک tblUserDetailDataTableDataRow دارید جهت دریافت نام کاربری آن (که همان فیلد UserName می باشد) به این صورت خواهید نوشت :
    MytblUserDetailDataTableDataRow.UserName


    DataTable:

    هر نمونه از این کلاس حاوی DataRow ها خواهد بود برای مثال وقتی شما لیست 3 کاربر موجود را در خواست کنید یک tblUserDetailDataTable حاوی 3 مورد tblUserDetailDataTableDataRow خواهید داشت

    TableAdapter:

    بله مجموع این اشیاء در واقع همان لایه دسترسی به داده ها ی(DAL) ما را ایجاد می کنند
    پس این کلاس بسیار مهم خواهد بود در واقع تمام اطلاعات خوانده شده از و نوشته شده در پایگاه داده توسط این این کلاس ها انجام می شود
    وقتی این کلاس به صورت خودکار ایجاد شد باز به صورت خودکار چهار عملیات اصلی کار با گایگاه داده (DELETE , UPDATE,INSERT,SELECT) نیز ایجاد شده و شما می توانید بدون درگیری با دستورات TSQL این عملیات را انجام دهید!

    اما خواهیم دید که در بعضی مکان ها این توابع و متد های خودکار جوابگوی تمام نیاز های ما نخواهند بود.
    پس راه حل چیست آیا باید باز توابع خودمان با پایگاه داده کار کنیم؟!

    خوشبختانه نیازی به این کار نیست زیرا این کلاس قابلیت سفارشی سازه فوق العاده بالای دارد در توابع بعدی می بینید که چگونه دستورات TSQL خود را به آنها اضافه و بصورت متد ها و توابع ساده از آنها استفاده خواهیم نمود

    آیا متد InitAdapters را به یاد دارید؟
    این همان متدی بود که تمام TableAdapter هایی را که ایجاد شده و مورد نیاز بودند را نمونه سازی و تنظیم نمودیم و همانطور که دید یک متغیر به نام AdpMgr نیز تعریف کردیم که حاوی یک نمونه از هر کدام از TableAdapter های موجود است پس زمانی که ما این متد را اجرا کردیم TableAdapter ها جهت استفاده آماده شدند

    به توضیح کد بالا (تابع GetUsersDetailList) می پردازیم:

    همانطور که می دانید وقتی می خواهیم لیست کاربران را بدست آوریم باید رکورد های جدول پایگاه داده را دریافت کنیم پس ما مجموعه ای از DataRow ها خواهیم داشت و همانطور که گفتیم این مجموعه به صورت DataTable نگه داری می شوند بنابراین مقدار برگشتی تابع از نوع DataTable خواهد بود و چون جدول مورد نظر ما tblUserDetail است کلاس مرتبط با آن tblUserDetailDataTable خواهد بود

    پس ابتدا یک متغیر از آن نوع که برگشت خواهیم داد ایجاد می کنیم(جهت مقدار دهی ، ویرایش و برگشت به عنوان نتیجه)

    در خط بعدی ما یکی از آن متد هایی را که به صورت خودکار ایجاد شده اند را استفاده می کنیم.متد GetData از هر TableAdapter کل رکود های موجود در جدول متناظر خود در پایگاه داده را باز می گرداند که در این نمونه برابر است با کد TSQL زیر:

    ُSELECT * FROM tblUserDetail


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

    پس وقتی ما این متد را فراخوانی کریدم مقدار برگشتی یک tblUserDetailDataTable خواهد بود که مقدار آن را در داخل متغیر تعریف شده در خط قبل قرار می دهیم
    خطوط بعدی جهت آماده سازی اطلاعات به کاربر می باشد

    همانطور که می دانید اگر خاصیت ایجاد خودکار ستون(AutoGenerateColumns) در یک کنترل Datagridveiw را با True تنظیم نموده و یک DataTable را به عنوان DataSurce به آن بدهیم به صورت خودکار اقدام به ایجاد یک ستون به ازای هر فیلد نموده و نام آنها را نیز با نام آن فیلد تنظیم می کند و همان را به عنوان سر ستون به کاربر نشان می دهد (برای مثال UserName) در حالی که برنامه با به زبان فارسی نوشته شده است پس ما نام هر ستون را به متناظر فارسی آن تبدیل می کنیم

    یک دلیل مهم دیگر هم به جداسازی لایه ها برمی گردد به این صورت که در این روش لایه رابط کاربری نیازی به دانستن نام فیلد ندارد ( که در توضیحات قسمت لایه کاربری هم مشاهد شد) و شما بعد ها می توانید نام فیلد یا حتی نوع منبع خود را تغییر دهید بدون آنکه نیازی به اعمال تغییرات در لایه PL داشته باشید

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

    تابع GetUser:

    کد:

     ''' <summary>
    ''' دریافت رکورد یک کاربر
    ''' </summary>
    ''' <param name="UserName"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetUser(UserName As String) As tblUserRow
    Dim Res = AdpMgr.tblUserTableAdapter.GetDataByUserName(UserN ame)
    If Res.Rows.Count = 0 Then
    Return Nothing
    Else
    Return Res.First
    End If
    End Function


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

    ولی یک جای کار میلنگد!
    ما از یک متد tblUserTableAdapter به نام GetDataByUserName استفاده کرده ایم که به صورت خودکار ایجاد نشده وجود هم ندارد!

    این متد از کجا آمده است؟!

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

    ممکن بگویید اینکه متد جدید لازم ندارد ما کل رکورد ها را دریافت و توسط یک حلقه رکورد مورد نظر را جدا و مورد استفاده قرار می دهیم

    باید گفت بله چنین عملیاتی کاملا ممکن است ولی به مشکلات آن دقت نشده است.شما فرض کنید در یک جدول یک میلیون رکورد دارید و شخص مورد نظر در آخرین رکورد قرار داد(و شما هم بی اطلاع هستید) در این حالت شما مجبورید کل اطلاعات یک میلیون رکورد را دریافت ( باتوجه به محدویت رم ، ترافیک شبکه و ...) و یک میلیون بار حلقه را اجرا کنید تا به رکورد مورد نظر برسید و کاربر را همچنان منتظر نگه داشته اید.

    آیا بهتر نبود به صورت مستقیم سراغ آن رکورد می رفتیم؟

    پس اگر قانع شدید آماده شوید تا کار سفارشی سازی را انجام دهیم

    ایجاد یک متد(دستور) جدید در Dataset:

    ابتدا Dataset را در حالت طراحی باز کنید(از Solution Explorer رو نام آن دوبار کلیک کنید)
    قصد ما ایجاد دستوری جدید برای عملیاتی بروی جدول tblUser می باشد پس جدول مورد نظر را یافته و انتخاب کنید(روی عنوان آن کلیک کنید)

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

    1-قسمت بالا که نام فیلد های ما مشاهده می شود

    این قسمت همان ساختار جدول است و یک DataRow از این جدول نیز چنین ساختاری دارد

    2-قسمت پایین که در حال حاظر فقط دارای یک مورد به نام GetData است (این نام برایتان آشنا نبود؟)

    این همان قسمت مورد نظر ما می باشد در واقع این همان TableAdapter این جدول است و ما همین قسمت را سفارشی سازی خواهیم کرد
    همانطور که می بیند متد GetData هم در آنجا حضور دارد

    خوب جهت شروع جدول را انتخاب و روی همان GetData کلیک راست کنید

    گزینه Add Query را انتخاب کنید

    در این قسمت چون ما قصد داریم با یک دستور TSQL که خود ایجاد می کنیم رکورد(ها) را انتخاب نماییم از پنجره باز شده گزینه Use SQL statement را انتخاب و دکمه Next را بزنید

    حال نوبت به انتخاب نوع عملیات رسیده است .اگر به تابع بالا دقت کرده باشید متوجه می شوید که ما نیازمند دریافت اطلاعات از پایگاه داده خواهیم بود و نیاز به کل یک رکورد داریم پس گزینه SELECT which returns rows را انتخاب و به مرحله بعدی بروید

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

    صبر کنید مشکلی در کار است!!!

    حالا ما باید چگونه به متد بگوییم کدام کاربر مد نظر ما می باشد ، ما که اینجا فقط می توانیم مقادیر ثابت را در ستور بنویسیم؟

    نگران نباشید راه حلی وجود دارد:

    اگر در مواردی همچون این مورد نیاز به ارسال پارامتر به متد TableAdapter جهت جاگذاری در ستور TSQL بود می توان آن پارامتر را با علامت @ تعریف نمود
    پس ما دستور TSQL رو به صورت زیر تغییر می دهیم

    SELECT UserName, PassWord FROM dbo.tblUser WHERE LOWER(UserName) = LOWER(@UserName)


    طبق دستور بالا متد ما یک پارامتر به نام UserName دریافت خواهد نمود و پس از دریافت مقدار پارامتر را با UserName@ جایگزین و دستور را اجرا خواهد نمود.(چون عرف آن است که نام کاربری حساس به کوچکی و بزرگی حروف نباشند به همین دلیل هر دو طرف به حالت حروف کوچک تبدیل و مورد مقایسه قرار می گیرند)

    نکته:

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

    یکی از مهمترین دلایل این کار جلوگیری از حملات معرف به SQL Injection است که حد خطر آن غیر قابل تصور است و سمی مهلک است و نه تنها اطلاعات و پایگاه داده شما بلکه کل سرور و حتی رایانه ای که سرور روی آن در حال اجرا است می تواند مورد حمله هکران و افراد داری نیات سوء قرار گیرد.
    چون توضیح این مطلب در این مکان ممکن نیست از وارد شدن به آن خودداری می کنیم ولی در آموزش های پیشرفته این موضوع نیز مورد بررسی قرار می گیرد.

    نکته:

    جهت آموزش و قبل از ورود به بحث SQL Injection در برنامه ما نقطه (های) نفوذی وجود خواهد داشت که باهم آن را پیدا و رفع خواهیم نبود.البته تا آن مقطع ، مکان و زمانی که آن نقطه بوجود آمده برای شما نامعلوم خواهد بود مگر آنکه خود آن را بیابید یا منتظر باشید که ما به شما بگوییم!

    به ادامه مطلب اصلی می پردازیم:
    تا اینجا ما دستور را ایجاد نمودیم پس دکمه Next را زده وارد مرحله بعدی شوید

    حال باید به متد و تابع ایجاد شده نامی تعیین کنید پس نام ها را به ترتیب FillDataByUserName و GetDataByUserName را وارد کنید

    چرا دو نام وارد شد؟
    در واقع متدی که با Fill مشخص است یک DataTable را دریافت و اطلاعات دریافتی را در داخل می ریزد و تابعی که با Get مشخص است اطلاعات دریافتی از پایگاه داده را به صورت یک DataTable به فرخوان باز می گرداند

    حال Finish را جهت اتمام عملیات کلیک کنید

    کار ما در لایه (DAL) تمام شد و دستور آماده استفاده است بدون آنکه لایه های بالاتر از چند و چون قضیه باخبر باشند آنها فقط یک پارامتر ارسال و نتیجه را دریافت خواهند کرد(جالب نیست!)

    تابع بعد از دریافت اطلاعات بررسی می کند که اگر رکوردی وجود داشت اولین رکود را به فرخوان بازگرداند در غیر این صورت یک مقدار پوچ (Nothing) برگشت داده می شود که نشان دهنده عدم وجود کاربر(رکورد) مورد نظر می باشد

    نکته:
    از این پس ما دیگر مراحل ایجاد متد های سفارشی را اینگونه شرح نخواهیم داد و فقط نام متد و دستور TSQL را (آن هم در صورت ضرورت) گفته و کار ایجاد متد با شما خواهد بود
    فقط به خاطر داشته باشید در آن پنجره ای که نوع عملیات را انتخاب کردیم گزینه انتخاب شده وابسته به نوع دستور می باشد برای مثال چنانچه دستور TSQL از نوع UPDATE بود باید گزینه متناظر آن یعنی همان UPDATE انتخاب شود با این کار دستور پیشنهادی ویزارد نیز به آن نوع تغییر خواهد کرد و کار شما هم آسان تر می شود

    تابع GetUserDetail:

    کد:

     ''' <summary>
    ''' دریافت مشخصات یک کاربر
    ''' </summary>
    ''' <param name="UserName">نام کاربری</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetUserDetail(UserName As String) As tblUserDetailRow
    Dim Res = AdpMgr.tblUserDetailTableAdapter.GetDataByUserName (UserName)
    If Res.Rows.Count = 0 Then
    Return Nothing
    Else
    Return Res.First
    End If
    End Function


    این تابع هم همانند تابع قبل است و این یکی مشخصات یک کاربر را بر می گرداند
    متد استفاده شده tblUserDetailTableAdapter.GetDataByUserName را با دستور TSQL زیر در TableAdapter مربوط به جدول tblUserDetail ایجاد کنید :

    SELECT UserName, FirstName, LastName, CreateDate, LastLogin FROM dbo.tblUserDetail
    WHERE LOWER(UserName) = LOWER(@UserName)



    تابع AddNewUser:

    کد:

     ''' <summary>
    ''' ایجاد یک کاربر جدید
    ''' </summary>
    ''' <param name="UserName">نام کاربری جدید</param>
    ''' <param name="Password">کلمه عبور</param>
    ''' <param name="FirstName">نام</param>
    ''' <param name="LastName">نام خانوادگی</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function AddNewUser(UserName As String, Password As String, _
    FirstName As String, LastName As String) As Boolean
    Try
    UserName = UserName.Trim
    FirstName = FirstName.Trim
    LastName = LastName.Trim
    If UserName.Length = 0 Then
    Throw New Exception("نام کاربری نامعتبر!")
    End If
    If Password.Length = 0 Then
    Throw New Exception("کلمه عبور نامعتبر!")
    End If
    If FirstName.Length = 0 Then
    Throw New Exception("نام نامعتبر!")
    End If
    If LastName.Length = 0 Then
    Throw New Exception("نام خانوادگی نامعتبر!")
    End If
    If GetUser(UserName) IsNot Nothing Then
    Throw New Exception("این نام کاربری موجود می باشد!")
    End If
    OpenConn(GlobalConnection)
    Dim trans = GlobalConnection.BeginTransaction
    AdpMgr.tblUserTableAdapter.Transaction = trans
    AdpMgr.tblUserDetailTableAdapter.Transaction = trans
    Dim encrpPassword As String = Strings.Left(StringCoding(Password), 1000)
    AdpMgr.tblUserTableAdapter.Insert(UserName, encrpPassword)
    AdpMgr.tblUserDetailTableAdapter.Insert(UserName, FirstName, LastName, PersianDate(Now), "")
    trans.Commit()

    Return True
    Catch ex As Exception
    Throw ex
    Finally
    CloseConn(GlobalConnection)
    End Try
    End Function


    کار این تابع از نام آن پیداست و معلوم می شود که این تابع باید یک کاربر جدید ایجاد کند
    قسمت اعتبار سنجی نیازی به توضیحات ندارد
    پس از کد زیر شرح داده می شود:


    OpenConn(GlobalConnection)
    Dim trans = GlobalConnection.BeginTransaction
    AdpMgr.tblUserTableAdapter.Transaction = trans
    AdpMgr.tblUserDetailTableAdapter.Transaction = trans
    Dim encrpPassword As String = Strings.Left(StringCoding(Password), 1000)
    AdpMgr.tblUserTableAdapter.Insert(UserName, encrpPassword)
    AdpMgr.tblUserDetailTableAdapter.Insert(UserName, FirstName, LastName, PersianDate(Now), "")
    trans.Commit()

    Return True


    جهت اینکه از نکات ساده تر شروع شود باید گفت که کد بالا را می توانستیم به شکل ساده زیر بنویسیم:


    Dim encrpPassword As String = Strings.Left(StringCoding(Password), 1000)
    AdpMgr.tblUserTableAdapter.Insert(UserName, encrpPassword)
    AdpMgr.tblUserDetailTableAdapter.Insert(UserName, FirstName, LastName, PersianDate(Now), "")
    Return True


    پس ابتدا به شرح کد دوم می پردازیم:

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

    خط دوم با توسط یکی از همان متد ای خودکار یک رکورد به جدول کاربران اضافه می کند

    خط بعدی هم یک رکورد به جدول مشخصات کاربر اضافه می کند

    و چنانچه عملیات با موفقیت انجام شد این اتفاق با True به اطلاع فراخوان خواهد رسید

    تعجب کردید که چرا در حالی که ما می توانیم این کد را بنویسیم و هیچ مشکلی هم وجود ندارد چرا خود را درگیر باز و بسته کردن اتصال و تراکنش ها کرده ایم!

    درست الان هیچ مشکل بالفعلی وجود ندارد آیا مشکلات بالقوه را نیز در نظر گرفته اید؟

    فرض کنید خط مربوط به ایجاد کاربر جدید اجرا و در پایگاه داده اعمال شد ولی در خط بعدی یعنی افزودن مشخصات کاربر به هر دلیلی( برای مثال طول بیش از حد نام خانوادگی که نباید بیش از 255 کاراکتر باشد) خطایی رخ داد و تابع از ادامه کار باز ایستاد

    حال ما چه داریم؟
    کاربری که در جدول اصلی ثبت شده ولی مشخصات آن ثبت نشده است!

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

    با این تفاسیر تکلیف چیست؟ آیا باید دستور TSQL جدید بنویسیم؟!

    راه بهتری وجود دارد:

    آیا تعریف تراکنش (Transaction) را که در بخش اصطلاحات بیان نمودیم به خاطر دارید

    "تازمانی که کل عملیات درون تراکنش با موفقیت انجان نشده و تراکنش نیز اعمال (Commit) نشود تغییرات به صورت قطعی در پایگاه داده وارد نخواهد شد."

    پس ما می توانیم هر دو عمل بالا را در داخل یک تراکنش انجام دهیم و در صورت موفق بودن هر دو عملیات تغییرات را اعمال نماییم

    برای انجام اینکار یک تراکنش را برای اتصال شروع می کنیم اما تا اتصال باز نباشد این عمل ممکن نیست پس ابتدا اتصال را باز و با فراخوانی Dim trans = GlobalConnection.BeginTransaction یک تراکنش را شروع و یک شیئ SqlTransaction دریافت می کنیم

    ولی عملیات کامل نشده است ! درست است که ما تراکنش را ایجاد کرده ایم ولی TableAdapter ها از وجود آن خبری ندارند

    بنابراین ما تراکنشی را که آغاز کرده ایم و اطلاعات آن درون متغیر trans قرار دارد را به TableAdapter ها معرفی می کنیم تا عملیات خود را درون آن انجام دهند

     AdpMgr.tblUserTableAdapter.Transaction = trans
    AdpMgr.tblUserDetailTableAdapter.Transaction = trans


    خوب حال عملیات را شروع می کنیم

    اگر عملیات موفقیت آمیز بود تغییرات در پایگاه داده اعمال می شود:
     
    trans.Commit()

    و نتیجه برگشت داده می شود

    اگر خطایی رخ داد چه؟

    هیچ! چون ما هنوز تغییرات را اعمال نکرده ایم بعد از بروز خطا خطوط بعدی اجرا نمی شوند (Commit اجرا نمی شود) و اجرا وارد بدنه Catch می شود و آن نیز خطا را ارسال می کند. ولی قبل خروج کلی از تابع طبق قانون باید بدنه Finally هم اجرا شود

    در بدنه Finally اتصال بسته می شود و در همین لحظه (طبق توضیحات بخش اصطلاحات) عمل بازگشت(RollBack) انجام شده تغییرات انجام شده در پایگاه داده از بین می رود

    و به همین دلیل است که ما عملیات بسته شدن اتصال را به بدنه Finally آورده ام به هر حال چه عملیات موفق باشد یا خطایی رخ دهد در نهایت اتصال باز شده باید بسته شود و طبق قانون Try ... Catch در هر شرایطی بدنه Finally باید اجرا شود پس چه مکانی بهتر از اینجا!

    نکته:
    توجه کنید که عملیات های چند تایی در دستورات حذف (DELETE) حساس تر و خطرناک تر هستند! و بی چون و چرا باید از تراکنش استفاده شود.

    تابع EditUser:

    کد:

     ''' <summary>
    ''' ویرایش کاربر
    ''' </summary>
    ''' <param name="UserName">نام کاربری</param>
    ''' <param name="Password">کلمه عبور جدید</param>
    ''' <param name="FirstName">نام جدید</param>
    ''' <param name="LastName">نام خانوادگی جدید</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function EditUser(UserName As String, Optional Password As String = "", _
    Optional FirstName As String = "", Optional LastName As String = "") As Boolean
    Try
    UserName = UserName.Trim
    FirstName = FirstName.Trim
    LastName = LastName.Trim
    Dim ExistUser = GetUser(UserName)
    Dim ExistUserDeail = GetUserDetail(UserName)
    If ExistUser Is Nothing OrElse ExistUserDeail Is Nothing Then
    Throw New Exception("این کاربر موجود نمی باشد!")
    End If
    If Password.Length > 0 Then
    Dim encrpPassword As String = Strings.Left(StringCoding(Password), 1000)
    ExistUser.PassWord = encrpPassword
    End If
    If FirstName.Length > 0 Then
    ExistUserDeail.FirstName = FirstName
    End If
    If LastName.Length > 0 Then
    ExistUserDeail.LastName = LastName
    End If
    OpenConn(GlobalConnection)
    Dim trans = GlobalConnection.BeginTransaction
    AdpMgr.tblUserTableAdapter.Transaction = trans
    AdpMgr.tblUserDetailTableAdapter.Transaction = trans
    AdpMgr.tblUserTableAdapter.Update(ExistUser)
    AdpMgr.tblUserDetailTableAdapter.Update(ExistUserD eail)
    trans.Commit()
    CloseConn(GlobalConnection)
    Return True
    Catch ex As Exception
    Throw ex
    Finally
    CloseConn(GlobalConnection)
    End Try
    End Function


    توضیح کد:

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

    با توجه به اینکه ممکن است قصد تغییر تمام مشخصات را نداشته باشیم پس بررسی می نماییم که چنانچه پارامتر آن ارسال شده باشد اقدام به تغییر مشخصات نماییم

    در ادامه اتصال باز ، تراکنش ایجاد و معرفی می شود

    بعد از متد توکار TableAdapter یعنی Update که یک DataRow دریافت و طبق آن پایگاه داده را بروز رسانی می کند استفاده می نماییم
    و در نهایت تغییرات اعمال می شود


    تابع DeleteUser:

    کد:

     ''' <summary>
    ''' حذف یک کاربر موجود
    ''' </summary>
    ''' <param name="UserName">نام کابری</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function DeleteUser(UserName As String) As Boolean
    Try
    UserName = UserName.Trim
    If GetUser(UserName) Is Nothing Then
    Throw New Exception("این کاربر موجود نمی باشد!")
    End If
    If CurrentUserName.ToLower = UserName.ToLower Then
    Throw New Exception("شما نمی توانید کاربر جاری را حذف کنید" & vbNewLine &
    "جهت انجام این کار باید با یک کاربر دیگر داری مجوز کافی وارد شوید")
    End If
    Dim AllUsersList = AdpMgr.tblUserTableAdapter.GetData
    If AllUsersList.Rows.Count <= 1 Then
    Throw New Exception("نرم افزار حداقل باید داری یک کاربر باشد")
    End If

    OpenConn(GlobalConnection)
    Dim trans = GlobalConnection.BeginTransaction
    AdpMgr.tblUserTableAdapter.Transaction = trans
    AdpMgr.tblUserDetailTableAdapter.Transaction = trans
    AdpMgr.tblUserPremissionTableAdapter.Transaction = trans
    AdpMgr.tblUserPremissionTableAdapter.DeleteUser(Us erName)
    AdpMgr.tblUserDetailTableAdapter.DeleteUser(UserNa me)
    AdpMgr.tblUserTableAdapter.DeleteUser(UserName)
    trans.Commit()
    Return True
    Catch ex As Exception
    Throw ex
    Finally
    CloseConn(GlobalConnection)
    End Try
    End Function


    این تابع وظیفه حذف یک کاربر را بر عهده دارد

    ولی عملیات حذف دارای قوانین بیشتر و حساس تری است:

    قوانین:

    1-کاربر باید موجود باشد

    2-همه کاربران را نمی شود حذف کرد :
    حداقل یک دلیل برای این کار وجود دارد.اگر همه کاربران حذف شوند دیگر کاربری جهت ورود به سیستم باقی نخواهد ماند

    3-کاربر جاری نمی تواند حذف شود: اگر این کار انجام شود ما در حال استفاده از کاربری خواهیم بود که وجود ندارد!

    (این قوانین بیشتر خواهند شد)

    بعد از گذراندن این قوانین اقدام به حذف کاربر از هر سه جدول مربوط به کابران می شود
    ولی این بار هم باید یک متد سفارشی بسازیم
    درست است که ما یک متد توکار جهت انجام این کار داریم ولی تعداد پارامتر های این یکی خیلی بیشتر است (مخصوصا که سه جدول داریم) در حالی که ما نیاز به دانستن و ارسال تمام آنها نداریم پس متد ها را با استفاده از دستورات زیر و در جداول مناسب ایجاد کنید (با توجه به نام جدول موجوددر داخل هر دستور):

    DELETE FROM [dbo].[tblUser] WHERE LOWER(UserName)=LOWER(@UserName)
    DELETE FROM [dbo].[tblUserDetail] WHERE LOWER(UserName)=LOWER(@UserName)
    DELETE FROM [dbo].[tblUserPremission] WHERE LOWER(UserName) = LOWER(@UserName)


    ولی اگر دقت کنید نکته مهمی در این تابع نهفته است!
    نکته در ترتیب قرار گیری دستور حذف ها می باشد

    آیا مطالب مربوط به روابط بین جداول و پدر و فرزندی را به یاد می آورید؟ اصل جامعیت داده ها را چطور؟
    بله درست است ما گفتیم نباید در پایگاه داده هیچ فرزندی وجود داشته باشد که پدر نداشته باشد (یتیم بودن) چه به صورت دائمی و چه به صورت موقت و در داخل یک تراکنش
    حتی گفتیم که اگر قرار باشد پدر و فرزندانش حذف شوند ابتدا باید تمام فرزندان سپس پدر حذف شود

    نتیجه این می شود که چون جدول tblUser پدر دو جدول دیگر می باشد ابتدا باید کاربر از آن دو و در نهایت از این جدول حذف شود در غیر اینصورت DBMS (سیستم مدیریت پایگاه داده) یک خطا را راه اندازی و عملیات را لغو خواهد نمود(می توانید امتحان کنید)



    نکات بخش:
    همانطور که دید ما به واسطه برنامه نویسی لایه ای در رابط کاربری و حتی لایه میانی حتی یک دستور TSQL هم نداریم و کارها چنان تقسیم بندی شده اند که لایه ها را می شود مستقل از هم دید برای مثال چنانچه روزی پایگاه داده خود را از SQL Server به Oracel یا اکسس و ... تغییر دهید نیازی به تغییر در فرم ها و کد های آنها نخواهید داشت
    و تصور کنید اگر تمام کد ها را در فرم ها نوشته بودیم علاوه بر اینکه مجبور بودیم کد های فراوانی را در هر فرم تکرار کنیم مدیریت آنها نیز کار آسانی نبود و یافتن یک خطا شما را ممکن بود از کل برنامه دلسرد کند

    علاوه بر آن وقتی شما از Dataset استفاده می کنید تا حد خیلی بالایی خود را از خطر های امنیتی همچون SQL Injection دور می کنید

    دید که کد نویسی به این سبک بسیار راحت تر و شیرین تر از روشی است که همیشه دستورات TSQL رو در پیش رو دارید و به نوعی به شما دهن کجی کرده و با هربار دیدن آنها داغ خطا های قبلی برنامه شما تازه می شود

    نکته بسیار مهم:

    باز هم تاکید می کنیم قبل انجام کوچکترین تغییری در دیتا ست حتی اگر قصد باز کردن آن در حالت طراحی را نمودید حتما از پروژه خود یک نسخه پشتیبان تهیه کنید زیرا گاهی به دلایل نامعلومی Dataset رفتار های عجیبی از خود نشان می دهد( به قول یکی از دوستانم دیوانه می شود)




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

  22. #22
    کاربر دائمی آواتار فرید نجفلو
    تاریخ عضویت
    بهمن 1390
    محل زندگی
    تبریز
    پست
    1,189

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    فعلا تاپیک در حال ایجاد است لطفا تا تکمیل مراحل اولیه ایجاد تاپیک از ارسال هرگونه پستی خودداری نمایید
    آخرین ویرایش به وسیله فرید نجفلو : جمعه 26 آبان 1391 در 22:07 عصر

  23. #23

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    سلام و با تشکر از آقای نجفلو عزیز

    اولا که خیلی وقته از تاپیک متوقف شده اما سوالم رو همین جا از آقای نجفلو میپرسم.

    *- من طبق گفته های شما جلو رفتم حالا رسیدم به گزارشگیری

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

    اصلا روش گزارشگیری رو توضیح میدید؟؟؟



    ''' <summary>
    '''مقدار دهی به ابزار ها
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub InitAdapters()
    Try
    AdpMgr.Connection = GlobalConnection
    AdpMgr.tblAnbarKalaGroupTableAdapter = New tblAnbarKalaGroupTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblAnbarTableAdapter = New tblAnbarTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblDbVerTableAdapter = New tblDbVerTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaGroupTableAdapter = New tblKalaGroupTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaInputTableAdapter = New tblKalaInputTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaOutputTableAdapter = New tblKalaOutputTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblKalaTableAdapter = New tblKalaTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblMoshtariTableAdapter = New tblMoshtariTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblPremissionListTableAdapter = New tblPremissionListTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblUserDetailTableAdapter = New tblUserDetailTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblUserPremissionTableAdapter = New tblUserPremissionTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.tblUserTableAdapter = New tblUserTableAdapter With {.Connection = GlobalConnection}
    AdpMgr.Table1TableAdapter = New Table1TableAdapter With {.Connection = GlobalConnection}
    Catch ex As Exception

    End Try
    End Sub


    حالا وقتی یک View به دیتاست اضافه کنم AdpMgr مقدار view رو در خودش نداره !!!؟؟؟

    لطفا توضیح میدید.

  24. #24

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام

    ******************************************


    آقای نجفلو ما همچنان چشم به راه شماییم.

    لطفا نحوه گزارش از view رو بفرمایید.

    با تشکر
    آخرین ویرایش به وسیله HM2020 : سه شنبه 22 بهمن 1392 در 19:56 عصر

  25. #25

    نقل قول: برنامه نویسی پایگاه داده به صورت گام به گام


    آقا کسی نیست جواب ما رو بده؟؟؟؟؟؟؟

    ای بابا عجب گیری کردیماااااااااااااا

قوانین ایجاد تاپیک در تالار

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