ورود

View Full Version : مشکل با recordset



حمیدرضاصادقیان
یک شنبه 11 آذر 1386, 14:49 عصر
سلام دوستان.یک مشکلی با Recordset دارم اینه که وقتی روی تعداد رکوردهای پایین دستور زیر را اجرا میکنم مشکلی نداره ولی در رکوردهای بالا تمامی محاسبات را اشتباه محاسبه میکنه.حتی کی حلقه رو به طور درست طی نمیکنه.و اعداد اصلا به ترتیب نیستند.


while not(adoquery1.recordset.eof) do
begin
a:=adoquery1.fieldvalues['no']+a;
adoquery1.recordset.movenext;
end;

JAFO_IRAN
یک شنبه 11 آذر 1386, 17:24 عصر
سلام

1. ADOQuery ابزار خوبی نیست - فقط برای اینکه شبیه به queryهای قبلی BDE باشه نوشته شده. با کمی کار میشه از ADODataSet استفاده کنی

2. در پیاده سازی دلفی روی ADO، اکثر کارها به recordset ارسال میشه اما ممکنه که برعکس این داستان صحیح نباشه - یعنی مثلا تغییر recordset منجر به بروز شدن بافرهای داخلی dataset دلفی نشه - یعنی movenext مثل ADOQuery1.Next عمل نکنه

3. بهترین کار اینه که با همان Next کار کنید و اگر سرعت بیشتر میخواهید مثلا به شکل زیر بنویسید:



ADODS.DisableControls;
try
fldA := ADODS.FieldByName('no');
ADODS.First;
while not ADODS.Eof do
begin
a := fldA.AsInteger + a;
ADODS.Next;
end;
finally
ADODS.EnableControls;
end;


ارادت

Cave_Man
یک شنبه 11 آذر 1386, 17:51 عصر
سلام

1. ADOQuery ابزار خوبی نیست - فقط برای اینکه شبیه به queryهای قبلی BDE باشه نوشته شده. با کمی کار میشه از ADODataSet استفاده کنی
یعنی چی میشه بیشتر توضیح بدی؟

JAFO_IRAN
یک شنبه 11 آذر 1386, 20:53 عصر
سلام

تا قبل از اینکه ADO در دلفی پیاده بشه، دلفی ابزار BDE رو داشت که با درایورهای خودش با DBMngrها وصل میشد. با اون میشد با Paradox، Oracle یا حتی SQL Server وصل شد.

BDE دو تا موجود مهم داشت که البته هنوز هم هستند: TTable و TQuery.

بعدها Microsoft یک سری ActiveX به نام ADO درست کرد. برای کار با DBهایی مثل SQL Server یا JetDB (یا همون Access) کار با ADO راحت تر یا بهتر بگم Nativeتر انجام میشه.

دلفی هم خیلی قشنگ این ADO رو پیاده کرد که به صورت ADOConnection و ADODataSet و ADOCommand میشه باهاش کار کرد.

حالا اونهایی که قبلا یک عالمه برنامه BDE نوشته بودند و میخواستن به ADO تبدیل کنند، باید خیلی تغییر در کدهاشون ایجاد میکردند. برای اینکه این تغییرات حداقل بشه (فقط برای اونهایی که میخواستند migrate کنند) دوتا موجود اضافی هم در سری موجودات ADO درست کرد که همان ADOQuery و ADOTable باشند. میشه با حداقل زحمت کدهایی که با TTable و TQuery نوشته شده بودند را با این دوتا موجود جدید جایگزین کرد.

اما چون روش ADO ماهیاتا با روش BDE فرق داره، به زودی معلوم شد که ADOQuery خیلی خوب و روان کار نمیکنه. به همین دلیل توصیه شد که اگر خواستین این بابا رو سریع تر کنید، بد نیست بعضی وقتها کدهای دلفی رو دور بزنید و مثلا از recordset (که interface مستقیم به Microsoft ADO باشه) به صورت مستقیم استفاده کنید.

در مقابل ADODataSet و ADOCommand بیشتر با متدلوژی Microsoft مطابقت دارند و اگر یک کم در کد نویسی دقت بشه، تقریبا وجودشون به عنوان موجودات مصرف کننده resource یا زمان احساس نمیشه. به همین دلیل نیازی هم به دور زدنشون پیش نمیاد.

امیدوارم مفید باشه...

ارادت

حمیدرضاصادقیان
دوشنبه 12 آذر 1386, 07:11 صبح
ممنون.ولی دوست عزیز کدی که شما نوشتین رو من تست کردم ولی در سرعت مانند Recordset نیست.زیرا من اول تمامی کارها رو انجام میدم بعد dataset رو به گرید وصل میکنم.عملا تاثیر آنچنانی نداره.حتی اقای کشاورز گفتند که اگه بعد از اتمام عملیات dataset را به گرید وصل کنید باز از کد فوق استفاده کنید سرعت بالایی خواهد داشت.ولی روی سیستم من که اینطور عمل نمیکنه.

sasan_vm
دوشنبه 12 آذر 1386, 08:21 صبح
سلام
به نظر من هم فرقی بین استفاده این دو ابزار نیست.



Re: ADOQuery vs. ADODataSet

From: Brian Bushay TeamB (BBushay_at_Nmpls.com)
Date: 02/03/04
Date: Mon, 02 Feb 2004 21:28:22 -0600


>I normally use TADOQueries in my applications, but I have seen people using
>TADODataSet instead.
>
>I have read something about ADO, but I don't see the point of using
>TADODataSet directly in Delphi, maybe because I was a BDE user.
>
>What is the positive side of using TADODataSets instead of TADOQueries?.
>Resource, speed?.
There is no difference in speed or resources. Borland recommends you use
TadoDataset because that is closer to how they are designing new dataset
components.

--Brian Bushay (TeamB)Bbushay@NMPLS.com

http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.database.ado/2004-02/0133.html

JAFO_IRAN
دوشنبه 12 آذر 1386, 11:16 صبح
با سلام و ارادت

دوست عزیر جناب ساسان

آقای Brian در بخش MIDAS جزء TeamB هستند و در اون زمینه احتمالا صاحب نظر. در مورد کل این مسائل (که البته یک بحث خیلی قدیمی در فروم‌های دلفی هست) مقاله زیر شاید مفید باشه (تشکر از قابیل که اصل link رو ایشون به من معرفی کرد)...

http://dn.codegear.com/article/27790

دوست عزیز جناب آقای صادقیان

در مورد خاص شما، حرفتان حتما صحیحه و لابد تفاوت سرعت وجود داره... دستهای ما بالاست و تسلیم؛ فقط یک نکته هم هست که بی زحمت این را هم تست کنید: حتی وقتی Data aware control هم نداریم، DisableControls ممکنه باعث افزایش سرعت بشه؛ ولی باید قبل از Open یا Active کردن DataSet انجام بشه...

به هر حال کد ابتدایی اشکال داره (و پست هم به همین دلیل ارسال شده). اگر میخواهید مستقیما با recordset کار کنید، لازمه که کاملا از اون استفاده کنید _ یعنی برای بدست آوردن مقادیر فیلدها (یا حتی کنترل eof) نیز به سراغ recordset برید.

تجدید ارادت

حمیدرضاصادقیان
دوشنبه 12 آذر 1386, 15:36 عصر
ممنونم از پاسخ زیباتون.ولی میشه کاملتر توضیح بدین منظور شما ازاینکه فرمودید باید از همون اول سراغ Recordset برم چیه؟در مورد نکته ای هم که فرمودید من به اون صورت تست نکردم اونم تست میکنم جوابشو میذارم.با تشکر.

Cave_Man
دوشنبه 12 آذر 1386, 15:39 عصر
ممنونم از پاسخ زیباتون.ولی میشه کاملتر توضیح بدین منظور شما ازاینکه فرمودید باید از همون اول سراغ Recordset برم چیه؟در مورد نکته ای هم که فرمودید من به اون صورت تست نکردم اونم تست میکنم جوابشو میذارم.با تشکر.
اگر لینکی که در پست قبلی هست رو بخونی کاملا متوجه میشی که جریان از چه قراره

حمیدرضاصادقیان
دوشنبه 12 آذر 1386, 16:03 عصر
ممنون.من لینک بالا رو خودم در پستهای قبل در سایت گذاشتم به همین خاطر به recordset روی اوردم.حالا کدی که من نوشتم به شکل زیر است.


query1.CommandText:=s;
query1.DisableControls;
Query1.open;
Gauge1.MaxValue:=query1.RecordCount;
while not Query1.Eof do
begin
Query1.Next;
Gauge1.Progress:=Gauge1.Progress+1;
end;
query1.EnableControls;
d1.DataSet:=Query1;

من کد فوق رو روی یک برنامه جدید تست کردم فقط رکوردها رو خوندم و رد کردم .بدون استفاده از روش فوق روی 200000 رکورد حدود 10 ثانیه طول میکشه تا از ابتدا به انتها برسه.ولی با کد فوق چیزی حدود 3-4 ثانیه طول میکشه.در صورتی که با استفاده از recordset این زمان به 1 ثانیه میرسه.حالا کدی من گذاشتم در رویداد calcfield کدی برای محاسبه مقدار مانده قرار دادم.که برای هر رکورد باید اون محاسبات انجام بشه.با هر دوتا کد هیچ تفاوتی ایجاد نمیشه.ولی وقتی از Recordset استفاده میکنم زمان کاملا به حداقلش میرسه.مثلا روی 10000 رکورد با هردو روش من تست کردم (هم با استفاده از disablecontrols هم بدون استفاده از آن) زمانی که میبره 9 ثانیه هست ولی با استفاده از recordset کمتر از یک چشم بهم زدن است.!!!!! در ضمن این نکته رو هم بگم که من adoquery رو به adodataset تبدیل کردم.

JAFO_IRAN
دوشنبه 12 آذر 1386, 16:12 عصر
سلام و ارادت

آقا چشمهای شما پاسخ ما رو زیبا میبینه....

عرض شود که منظورم این بود که همه کار رو با recordset انجام بدیم:



while Not ADOQuery1.Recordset.EOF do
begin
a := a + ADOQuery1.RecordSet.Fields[3].Value;
ADOQuery1.Recordset.Movenext;
end


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

ارادت

JAFO_IRAN
دوشنبه 12 آذر 1386, 16:23 عصر
باز هم سلام و ارادت

البته تفاوت بسیار قابل ملاحظه‌ای دیده میشه که باید بررسی بشه. با اون روش که همه چیز با recordset انجام بشه، البته شاید بشه به نتیجه رسید..

یک کم عجیبه اگه OnCalcField وقتی که با recordset کار میکنی fire بشه. ولی اگه اجرا میشه به نظر من هم بهتره از recordset استفاده کنی - ولی اگه OnCalc اجرا نمیشه ممکنه تفاوت زمان همین باشه. شاید بشه به جای OnCalcFields، عملیات رو در همین حلقه و با recordset انجام بدید...

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

تجدید ارادت

حمیدرضاصادقیان
دوشنبه 12 آذر 1386, 22:05 عصر
ممنون از پاسختون.اخه مشکل منم اینه که دقیقا oncalcfield فعال میشه روی رکوردهای پایین خوب جواب میده بعضی مواقع روی رکوردهای بالا هم درست جواب میده ولی در بعضی شرایط به مشکل برمیخوره.چیزی که خیلی ساده بود و خودم تست کردم این بود یک جدول موقت ایجاد کردم با یک فیلد و 100000 رکورد عدد داخلش اضافه کردم.بعد از اون با استفاده از Recordset در یک حلقه ساده این اعداد رو داخل یک listbox اضافه کردم میخواستم ببینم درست کار میکنه که دیدم فقط توی این حلقه ردیف شماره 1 رو برمیگردونه و توی یک حلقه بی نهایت افتاد.

vcldeveloper
سه شنبه 13 آذر 1386, 01:48 صبح
حتی اقای کشاورز گفتند که اگه بعد از اتمام عملیات dataset را به گرید وصل کنید باز از کد فوق استفاده کنید سرعت بالایی خواهد داشت.
ببخشید، ولی من همچین حرفی نزدم. اگر به آن تاپیکی که قبلا ایجاد کرده بودید مراجعه کنید، متوجه میشید که من استفاده از DisabledControls را توصیه کردم و گفتم که تصور می کردم در صورت متصل نبودن یک DataSource به DataSet، متد DisableControls تاثیر نداشته باشه، ولی با تستی که نتایجش را در همان تاپیک گذاشتم، متوجه شدم که DisableControls در هر صورت روی کاهش زمان مرور رکوردها موثر است.

حمیدرضاصادقیان
سه شنبه 13 آذر 1386, 08:22 صبح
درسته.ببخشید اقای کشاورز.مثلا منظور من هم همینی بود که شما گفتید. ;)

JAFO_IRAN
سه شنبه 13 آذر 1386, 11:25 صبح
سلام

در مورد اون مثال با Listbox و حلقه بی نهایت توجه شما رو دوباره به همون روش که گفتم (همه کارها با recordset) جلب میکنم. یعنی eof هم با recordset، اخذ مقدار فیلد و...

به هر حال من خودم سعی میکنم یکسری روال سنجش درست و حسابی رو دربیارم تا بالاخره این داستان قدیمی رو به یک سرانجام خوبی برسانیم (انشاءالله با کمک دوستان)




:
عرض شود که منظورم این بود که همه کار رو با recordset انجام بدیم:



while Not ADOQuery1.Recordset.EOF do
begin
a := a + ADOQuery1.RecordSet.Fields[3].Value;
ADOQuery1.Recordset.Movenext;
end




ارادت

حمیدرضاصادقیان
سه شنبه 13 آذر 1386, 14:50 عصر
باتشکر.من با همون روشی که شما فرمودید انجام دادم و مشکل حل شد و دیگه record ها اشتباه نمی شوند.فقط سوالم اینجاست که اگه در بعضی از قسمتهای برنامه از Recordset استفاده کنیم با بقیه قسمتها مشکلی ایجاد نخواهد کرد.(البته میدونم سوالم ابتدایی هست!)
این قسمتها هم عملا ربطی به هم ندارند.فقط اگه خواستم اط داخل اون dataset ها دیتایی رو بخونم باز باید از Recordset استفاده کنم؟ یا اونجا میشه از همین روال عادی استفاده کرد.

JAFO_IRAN
سه شنبه 13 آذر 1386, 15:28 عصر
سلام

فکر نمیکنم مشکلی داشته باشه - پیش فرض اینه که فقط برای عملیات تکراری روی تمام رکوردهای یک DataSet و در یک حلقه while از recordset استفاده میشه؛ به همین دلیل به بقیه DataSetها که اصلا ربطی نداره؛ برای خود اون DataSet هم برای محکم کاری خوبه پس از اتمام کار یکبار Close و Open کنید.

ارادت