ورود

View Full Version : سوال: کلاس DAL برای تغییرات در دیتابیس



saeed hg
پنج شنبه 16 تیر 1390, 20:29 عصر
من از متد سه لایه برای برنامه های پایگاه داده تحت C#.Net استفاده می کردم. و یکی از لایه هاش لایه اتصال و تغییر در دیتابیس هست(dal) . الان که با دلفی آشنا شدم و کلی با کنترل های ADO درگیر!! شدم می خوام یه لایه DAL با دلفی بنویسم . یکی از توابعی که تو این لایه هست تابع executesp هست که برای اجرای strore procedure استفاده میشه. واسه فرستادن پارامترها به این تابع میشه از رکورد یا آرایه استفاده کرد. هرکاری کردم نتونستم این کار رو بکنم . می خواستم کمکم کنید تا بتونم این مورد رو حل کنم. البته تعداد پارامترها متغیره. چون امکان داره یه store procedure دو تا پارامتر داشته باشه . یکی دیگه بیست تا. بعدشم باید اسم پارامتر و مقدارش رو به این تابع فرستاد . پس بهتره که از رکورد استفاده کرد. اگه در این مورد کمک کنید و کدش رو تغییر بدید ممنون میشم.

مورد دیگه اینکه من یه دیتا ماژول دارم و کنترل های ado روی اون قرار دارند . در رویداد Formcreate مربوط به فرم اصلی وقتی می خوام adoconnection1.connectionstring رو مقدار دهی کنم با پیغام خطا روبرو میشم یا همینطور اگه بخوام تابع prepareconnection رو برای مقداردهی اولیه فراخوانی کنم باز با همین خطا روبرو میشم. عکسش رو گرفتم بهمراه سورس برنامه میزارم. من کلاس DAL که قبلا برای C#.Net نوشتم رو برای راهنمایی بیشتر گذاشتم .

saeed hg
جمعه 17 تیر 1390, 15:51 عصر
please help me:ناراحت:

یوسف زالی
جمعه 17 تیر 1390, 19:02 عصر
سلام.
رفع مشکل اول:
برای فرستادن یک آرایه با طول متغیر ساده ترین راه استفاده از TStrings هست.
شما می تونی پارامتر ها رو شی هم بگیری مثلا یه ADODataSet بفرستی به Procedure که در این حالت تمام خصوصیات رو هم در دسترس داری.
یه راه دیگه فرستادن یه Open Array هست.
راه های دیگه ای هم داره...

رفع مشکل دو:
در سورس Application باید جای این دو را عوض کنید:


Application.CreateForm(TForm1, Form1);
Application.CreateForm(TDataModule2, dm2);



به دلیل ابنکه وقتی فرم شما داره ساخته میشه دیتاماژولی وجود نداره تا آیتم هاش رو تغییر بدی.

saeed hg
جمعه 17 تیر 1390, 21:07 عصر
بابت مشکل دوم دستتون درد نکنه .
اما مشکل اول . اگه نمومه برنامه سی شارو من رو دیده باشید من پارامترها رو با رکورد میفرستادم به تابع . که دارای ۲تا متغیر parname و parvalue هست.
for (i = 0;i<=datasend.GetUpperBound(0) ;i++)
{
sqlcom.Parameters.AddWithValue(datasend[i].parname, datasend[i].parvalue);
}

هرکاری می کنم نمی تونم چنین چیزی رو پیاده کنم . اگه لطف کنید و این قطعه کد رو برام بنویسید خیلی ممنون میشم.
یه مشکل دیگه اینکه تو یکی از توابع کلاس دیتابیس خطا رخ میده اول پیغام خطای خود دلفی نشون داده میشه وبعد که دوباره برنامه رو اجرا می کنم پیغام خطاییی که داخل بلوک except نوشتم نمایش داده میشه . و همین طور می خواستم پیغام خطایی که دلفی در رابطه با بانک اطلاعاتی نشون میده رو داخل پیغام خطای خودم بذارم . و دیگه پیغام خطای دلفی در رابطه با بانک رو نشون نده. اون Exception مربوط به sql رو نمیدونم چیه.

ازینکه وقت گذاشتید و رفع اشکال می کنید خیلی ممنونم.

saeed hg
جمعه 17 تیر 1390, 21:14 عصر
همینطور نظرتون رو درباره این کلاس می خواستم بدونم . چطوریه؟ خوب یا بد؟
فکر کنم کامپوننت های ADO رو تو توابع ایجاد کنم بهتر باشه . نیازی هم به اون دیتا ماژول نیست. اگه نظری درباره تغییرات و اضافه یا حذف کردن بعضی موارد دارید خیلی مشتاقم بشنوم.

یوسف زالی
شنبه 18 تیر 1390, 00:06 صبح
یه کد گذاشتم که با کمی دستکاری می تونی به هدفت برسی (استفاده از Open Array):
برای یونیت:


unit Unit2;
interface
uses
Classes;
type
TParam = record
Name: string;
Value: Variant;
end;
TQuery = array of TParam;
procedure P1(const param: TQuery);
implementation
uses
Dialogs, Variants;
procedure P1(const param: TQuery);
var
i: integer;
s: string;
begin
s := '';
for i := 0 to length(param) -1 do
s := s + ' ' + param[i].Name + ' = ' + VarToStr(param[i].Value);
ShowMessage(s);
end;
end.



در فراخوانی:


procedure TForm1.Button1Click(Sender: TObject);
var
p: TQuery;
begin
setlength(p, 3);
p[0].Name := 'Param1'; p[0].Value := 'Salam';
p[1].Name := 'Param2'; p[1].Value := 100;
p[2].Name := 'Param3'; p[2].Value := 25.73;
P1(p);
end;



اینکه try چرا دوبار ارور میده بر میگرده به Debug کردن کد دلفی. و در حالتی که exe تولید شده اجرا بشه دیگه دیده نمی شه.
دلفی با این کار برنامه نویس رو مطلع می کنه که برنامه دارای ارور هست تا برنامه نویس اگر خواست بتونه با زدن Ctrl + Alt + C وارد کد های اسمبلی بشه و ...
کلا اگر از try استفاده بشه در هنگام اجرا از IDE دلفی هم ارور نشون داده میشه هم Except شما.
اما در اجرا از Exe فقط بلوک Except.
برای اینکه ارور پیش فرض دلفی رو داشته باشید:


try
Your Code
except
on e: Exception do ShowMessage(e.Message);
end;



به جای Exception می تونید انواع جزیی تری را مثل EDivByZero بگذارید.
حالت کلی:


try
blabla
except
on e: EDivByZero do Something1;
on e: EOutOfResources do Something2;
.
.
else SomethingN;
end;



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

saeed hg
شنبه 18 تیر 1390, 09:13 صبح
می خواستم بدونم که یه نمونه برنامه دو لایه ساده می تونم ازتون درخواست کنم؟
البته هنوز لایه BL مونده که باید نوشته شه. اینطور که معموله کدش چنگی به دل نمیزنه . درسته؟
اون روش های کوتاهتر فرستادن پارامتر رو هم یه توضیح کوچک درموردش میدید؟

بازم بابت جواباتون منون

یوسف زالی
شنبه 18 تیر 1390, 16:29 عصر
آقا سعید تشکر که دکمه داره!!
خواهش می کنم.
ببینید ما از یه روش استفاده می کنیم که ممکنه خیلی ایراد داشته باشه - حتی ممکنه من به اشتباه فکر کنم برنامه من دولایه هست.
به این صورت که تمام کارهامون در SP های SQL هست و در دلفی تمام ADO ها رو روی DataModule می گذاریم که هر کدوم از SP ها یه ADO مخصوص خود دارند.
ADO هایی که برای Select استفاده دارند رو با دوبار کلیک روش فیلد هاشو Add می کنیم و در Grid به DataSource متناطر با ADO متصل می شیم.
این DataSource هم روی DataModule هست و DataSet اون رو ADO خودش متصله.
در کد نویسی هم پارامتر های ADO رو مستقیم مقدار میدیم.
روشی که من استفاده می کنم در حقیقت برنامه نوشته شده کس دیگه ای بوده که من گسترشش می دم.
اگر شما ابرادی وارد می دونید لطفا بگید. می دونم که احتمال اینکه در روند من اشکالی باشه زیاده.

اما روشهای کوتاهتر:
شما می تونید یک ADODataSet رو به عنوان یک پارامتر بفرستید. اما در خصوص مناسب بودن برای برنامه چند لایه نظری ندارم.
این شی رو هم قبل از فرستادن به تابع مورد نظر به راحتی مقدار دهی کنید و در تابع مورد نظر استفاده کنید.
برای اینکه مطمئن شید که در تابع مقدار اون رو تغییر نمی دید می تونید اون رو Const بفرستید.

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

saeed hg
شنبه 18 تیر 1390, 17:33 عصر
بازم ممنون. از دکمه تشکر زیاد خوشم نمیاد . من تو سی شارپ به این صورت برنامه می نویسم که اطلاعات رو از لایه UI یا همون لایه نمایش از کاربر می گیرم و به لایه بیزینس می فرستم . تو لایه بیزینس چند تا تابع واسه insert , update , delete, search,check primery key , check forign key و مقدار دهی اولیه به پارامترهای sql دارم . یه تابع هم واسه اعتبارسنجی دارم که تهی یا مقدار اشتباه رو تشخیص میده . خب اطلاعات رو تو یه آرایه میریزم و این آرایه رو برای حذف و اضافه و به روز رسانی به بیزینس میفرستم .مثلا برای اضافه کردن تو تابه insert چنین کدی دارم (تو سی شارپ):

public Boolean INSERT(string[] data)
{
if (valid(data))
if (check_primery_key(data[0]))
{

SQLFunc exesqlfunc = new SQLFunc();
SQLFunc.sqlparametr[] sqlpar = new SQLFunc.sqlparametr[10];
fill_sending_par(sqlpar, data);
if (exesqlfunc.comexenonquery("sp_insert_customer", sqlpar))
return true;
else
return false;

}

else
return false;

else
return false;

}

تو این کدهای بالا تابع

exesqlfunc.comexenonquery("sp_insert_customer", sqlpar)

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


public Boolean comexenonquery(string sql,sqlparametr[] datasend)
{
try
{
int i;

object connec = sqlcon;
if (connec == null)
{
openconnection();
}
sqlcom = new SqlCommand(sql, sqlcon);
sqlcom.CommandType = CommandType.StoredProcedure;
for (i = 0;i<=datasend.GetUpperBound(0) ;i++)
{
sqlcom.Parameters.AddWithValue(datasend[i].parname, datasend[i].parvalue);
}
sqlcom.ExecuteNonQuery();
MessageBox.Show("تغییرات با موفقیت اعمال گردید\n\n", "پیام", MessageBoxButtons.OK, MessageBoxIcon.Information);
return true;

}
catch (Exception ex)
{
MessageBox.Show("خطا در اعمال تغییرات \n\n" + ex.Message, "خطا", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
finally
{
closeconnection();

}
}


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

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

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

یوسف زالی
شنبه 18 تیر 1390, 19:24 عصر
بسیار خوشحال می شم که کد شما رو ببینم.
ممنون.

saeed hg
یک شنبه 19 تیر 1390, 10:03 صبح
سلام به آدرس yousijoon (yzposhtekhat@yahoo.com) فرستادم . البته چون آخرای مهلت تحویل پروژه بود و وقت نداشتم نرسیدم کاملش کنم.

saeed hg
جمعه 24 تیر 1390, 15:38 عصر
می خواستم بدونم می تونم این کلاس dal و data madule رو در وروژه های دیگه خودم استفاده کنم؟ چطوری اینکار رو انجام بدم . و همین طور درباره bpl package می خواستم بدونم . چطوری ازشون استفاده کنم ؟ می تونم اون data madule و unit dal رو در یک bpl قرار بدم؟

saeed hg
سه شنبه 28 تیر 1390, 11:14 صبح
please.. Help me