मैंने पिछले हफ्ते कुछ देखा जो मुझे उम्मीद नहीं थी, और नीचे वर्णित होगा। मैं उत्सुक हूं कि ऐसा क्यों होता है। क्या यह टीडीएटीसेट क्लास, टीडीबीजीड का एक आर्टिफैक्ट, या कुछ और आंतरिक है?डीबीजीड में कॉलम चलाना प्रतीत होता है संलग्न डेटासेट फ़ील्ड
खुले क्लाइंटडेटासेट में फ़ील्ड का क्रम बदल गया। विशेष रूप से, मैंने FieldDefs का उपयोग करके अपनी संरचना को परिभाषित करने के बाद CreateDatatSet को कॉल करके कोड में क्लाइंटडेटासेट बनाया है। इस क्लाइंटडेटासेट की संरचना में पहला फ़ील्ड StartOfWeek नामक दिनांक फ़ील्ड था। केवल कुछ ही क्षण बाद, कोड जो मैंने लिखा था, जो माना जाता है कि StartOfWeek फ़ील्ड शून्य स्थान पर था, ClientDataSet.Fields [0], विफल रहा, क्योंकि StartOfWeek फ़ील्ड क्लाइंटडेटासेट में पहला फ़ील्ड नहीं था।
कुछ जांच के बाद, मैंने सीखा कि यह संभव था कि क्लाइंटडेटासेट में प्रत्येक फ़ील्ड, किसी दिए गए पल में, क्लाइंटडेटासेट बनाया गया था, उस समय मूल संरचना से अलग स्थिति में दिखाई दे। मुझे पता नहीं था कि यह हो सकता है, और Google पर एक खोज ने इस प्रभाव का कोई उल्लेख नहीं किया है।
क्या हुआ जादू नहीं था। खेतों ने खुद को स्थिति नहीं बदल दी, न ही उन्होंने मेरे कोड में किए गए किसी भी चीज़ के आधार पर बदल दिया। ClientDataSet में फ़ील्ड को भौतिक रूप से बदलने के लिए खेतों के कारण क्या हुआ था कि उपयोगकर्ता ने डीबीजीड्रिड में कॉलम का क्रम बदल दिया था, जिस पर क्लाइंटडेटासेट संलग्न था (निश्चित रूप से डेटासोर्स घटक के माध्यम से)। मैंने डेल्फी 7, डेल्फी 2007 और डेल्फी 2010 में इस प्रभाव को दोहराया।
मैंने एक बहुत ही सरल डेल्फी एप्लिकेशन बनाया जो इस प्रभाव को प्रदर्शित करता है। इसमें एक डीबीजीड, डेटासोर्स, दो क्लाइंटडेटासेट्स और दो बटन के साथ एक ही फॉर्म होता है। इस फार्म की OnCreate ईवेंट हैंडलर निम्नलिखित
procedure TForm1.FormCreate(Sender: TObject);
begin
with ClientDataSet1.FieldDefs do
begin
Clear;
Add('StartOfWeek', ftDate);
Add('Label', ftString, 30);
Add('Count', ftInteger);
Add('Active', ftBoolean);
end;
ClientDataSet1.CreateDataSet;
end;
Button1, जो लेबल किया गया है दिखाएँ ClientDataSet संरचना की तरह लग रहा है, तो निम्न ऑनक्लिक ईवेंट हैंडलर में शामिल है।
procedure TForm1.Button1Click(Sender: TObject);
var
sl: TStringList;
i: Integer;
begin
sl := TStringList.Create;
try
sl.Add('The Structure of ' + ClientDataSet1.Name);
sl.Add('- - - - - - - - - - - - - - - - - ');
for i := 0 to ClientDataSet1.FieldCount - 1 do
sl.Add(ClientDataSet1.Fields[i].FieldName);
ShowMessage(sl.Text);
finally
sl.Free;
end;
end;
चलती फ़ील्ड प्रभाव का प्रदर्शन करने के लिए, इस एप्लिकेशन को चलाएं और क्लाइंटडेटासेट संरचना दिखाए गए बटन पर क्लिक करें। आप यहाँ दिखाया गया है ऐसा ही कुछ देखना चाहिए:
The Structure of ClientDataSet1
- - - - - - - - - - - - - - - - -
StartOfWeek
Label
Count
Active
इसके बाद, DBGrid के कॉलम खींचें क्षेत्रों के प्रदर्शन का क्रम फिर से व्यवस्थित करने के लिए। एक बार फिर क्लाइंटडेटासेट संरचना बटन पर क्लिक करें। इस बार आपको लगता है कि करने के लिए कुछ इसी तरह देखेंगे यहाँ दिखाया गया है:
The Structure of ClientDataSet1
- - - - - - - - - - - - - - - - -
Label
StartOfWeek
Active
Count
क्या इस उदाहरण के बारे में उल्लेखनीय बात यह है कि DBGrid के स्तंभ स्थानांतरित किया जा रहा है, लेकिन वहाँ में फील्ड्स की स्थिति पर एक स्पष्ट प्रभाव है ClientDataSet, जैसे कि क्लाइंटडेटासेट.फिल्ड [0] स्थिति में जो फ़ील्ड एक बिंदु पर था, वह क्षणों के बाद आवश्यक नहीं है। और, दुर्भाग्य से, यह स्पष्ट रूप से क्लाइंटडेटासेट समस्या नहीं है। मैंने बीडीई-आधारित टीटीबल्स और एडीओ-आधारित एडोटेबल्स के साथ एक ही परीक्षण किया और उसी प्रभाव को मिला।
यदि आपको किसी डीबीजीड में प्रदर्शित होने वाले क्लाइंटडेटासेट में फ़ील्ड का संदर्भ लेने की आवश्यकता नहीं है, तो आपको इस प्रभाव के बारे में चिंता करने की आवश्यकता नहीं है। आप में से बाकी के लिए, मैं कई समाधानों के बारे में सोच सकता हूं।
सबसे आसान, हालांकि इस समस्या से बचने के लिए सबसे आसान तरीका यह नहीं है कि उपयोगकर्ता को डीबीजीड में खेतों को पुन: व्यवस्थित करने से रोका जाए। यह DBResizeColumn ध्वज को डीबीजीड की विकल्प संपत्ति से हटाकर किया जा सकता है। हालांकि यह दृष्टिकोण प्रभावी है, यह उपयोगकर्ता के परिप्रेक्ष्य से संभावित मूल्यवान प्रदर्शन विकल्प को समाप्त करता है।इसके अलावा, इस ध्वज को हटाने से न केवल कॉलम रीडरिंग को प्रतिबंधित किया जाता है, यह स्तंभ आकार बदलने से रोकता है। (कैसे स्तंभ का आकार बदलने के विकल्प को हटाए बिना स्तंभ पुनर्व्यवस्था सीमित करने के लिए जानने के लिए, http://delphi.about.com/od/adptips2005/a/bltip0105_2.htm देखें।)
दूसरा वैकल्पिक हल उनके शाब्दिक स्थिति के आधार पर एक डेटासेट के क्षेत्रों की चर्चा करते हुए से बचने के लिए (के बाद से इस समस्या का सार है) है। शब्दों के क्रम में, यदि आपको गणना फ़ील्ड को संदर्भित करने की आवश्यकता है, तो DataSet.Fields का उपयोग न करें [2]। जब तक आप फ़ील्ड का नाम जानते हैं, तो आप डेटासेट.फिल्ल्डबीनाम ('गणना') जैसे कुछ का उपयोग कर सकते हैं।
हालांकि फील्डबीनाम के उपयोग के लिए एक बड़ी कमी है। विशेष रूप से, यह विधि फ़ील्ड नाम के आधार पर एक मिलान की तलाश में डेटासेट की फ़ील्ड्स प्रॉपर्टी के माध्यम से पुनरावृत्ति करके क्षेत्र की पहचान करती है। चूंकि यह हर बार जब आप FieldByName को कॉल करते हैं, तो यह एक ऐसी विधि है जिसे परिस्थितियों से बचा जाना चाहिए जहां फ़ील्ड को कई बार संदर्भित किया जाना चाहिए, जैसे एक लूप में जो एक बड़ी डेटासेट को नेविगेट करता है।
आप क्षेत्र को बार-बार (और कई बार की एक बड़ी संख्या) का उल्लेख करने की जरूरत है, तो निम्नलिखित कोड का टुकड़ा की तरह कुछ का उपयोग करें:
var
CountField: TIntegerField;
Sum: Integer;
begin
Sum := 0;
CountField := TIntegerField(ClientDataSet1.FieldByName('Count'));
ClientDataSet1.DisableControls; //assuming we're attached to a DBGrid
try
ClientDataSet1.First;
while not ClientDataSet1.EOF do
begin
Sum := Sum + CountField.AsInteger;
ClientDataSet1.Next;
end;
finally
ClientDataSet1.EnableControls;
end;
एक तीसरा उपाय है, लेकिन यह केवल उपलब्ध है जब आपका डेटासेट क्लाइंटडेटासेट होता है, तो मेरे मूल उदाहरण में से एक की तरह। उन परिस्थितियों में, आप मूल क्लाइंटडेटासेट का क्लोन बना सकते हैं, और इसमें मूल संरचना होगी। नतीजतन, शून्य क्षेत्र में जो भी क्षेत्र बनाया गया था, वह अभी भी उस स्थिति में होगा, चाहे उपयोगकर्ता ने डीबीजीड को क्या किया है जो क्लाइंटडेटासेट डेटा प्रदर्शित करता है।
यह निम्न कोड में प्रदर्शित किया गया है, जो क्लोन क्लाइंटडेटासेट संरचना लेबल वाले बटन के ऑनक्लिक ईवेंट हैंडलर से जुड़ा हुआ है।
यह:
procedure TForm1.Button2Click(Sender: TObject);
var
sl: TStringList;
i: Integer;
CloneClientDataSet: TClientDataSet;
begin
CloneClientDataSet := TClientDataSet.Create(nil);
try
CloneClientDataSet.CloneCursor(ClientDataSet1, True);
sl := TStringList.Create;
try
sl.Add('The Structure of ' + CloneClientDataSet.Name);
sl.Add('- - - - - - - - - - - - - - - - - ');
for i := 0 to CloneClientDataSet.FieldCount - 1 do
sl.Add(CloneClientDataSet.Fields[i].FieldName);
ShowMessage(sl.Text);
finally
sl.Free;
end;
finally
CloneClientDataSet.Free;
end;
end;
आप इस परियोजना चलाने के लिए और बटन दिखाएं नामक क्लोन ClientDataSet संरचना क्लिक करें, तो आप हमेशा ClientDataSet का सच संरचना, जैसा कि यहाँ दिखाया
The Structure of ClientDataSet1
- - - - - - - - - - - - - - - - -
StartOfWeek
Label
Count
Active
परिशिष्ट मिल जाएगा यह ध्यान रखना महत्वपूर्ण है कि अंतर्निहित डेटा की वास्तविक संरचना प्रभावित नहीं होती है। विशेष रूप से, यदि, डीबीजीड में कॉलम के क्रम को बदलने के बाद, आप ClientDataSet की SaveToFile विधि को कॉल करते हैं, सहेजी गई संरचना मूल (वास्तविक आंतरिक) संरचना है। साथ ही, यदि आप एक क्लाइंटडेटासेट की डेटा प्रॉपर्टी को दूसरे में कॉपी करते हैं, तो गंतव्य क्लाइंटडेटासेट भी वास्तविक संरचना दिखाता है (जो उस स्रोत के समान होता है जब स्रोत क्लाइंटडेटासेट क्लोन किया जाता है)।
इसी तरह, टीटीबल और एडोटेबल समेत अन्य परीक्षण किए गए डेटासेट से जुड़े डीबीजीआरआईड्स के कॉलम ऑर्डर में परिवर्तन, वास्तव में अंतर्निहित तालिकाओं की संरचना को प्रभावित नहीं करते हैं। उदाहरण के लिए, एक टीटीबल जो ग्राहक.db नमूना से डेटा प्रदर्शित करता है पैराडाक्स टेबल जो डेल्फी के साथ जहाज वास्तव में उस तालिका की संरचना को नहीं बदलता है (न ही आप इसकी अपेक्षा करेंगे)।
हम इन अवलोकनों से क्या निष्कर्ष निकाल सकते हैं यह है कि डेटासेट की आंतरिक संरचना स्वयं ही बरकरार है। नतीजतन, मुझे यह मानना चाहिए कि कहीं भी डेटासेट की संरचना का द्वितीयक प्रतिनिधित्व है। और, यह या तो डेटासेट (जो कि डेटासेट के सभी उपयोगों की आवश्यकता नहीं है) से जुड़ा हुआ प्रतीत होता है, डीबीजीड से जुड़ा हुआ है (जो डीबीजीड इस सुविधा का उपयोग कर रहा है, लेकिन जो अधिक समझ में नहीं आता है, लेकिन जो नहीं है अवलोकन द्वारा समर्थित है कि टीएफआईल्ड रीडरिंग डेटासेट के साथ ही जारी है), या कुछ और है।
एक और विकल्प यह है कि प्रभाव TGridDataLink से जुड़ा हुआ है, जो कक्षा है जो मल्टीरो-जागरूक नियंत्रण (जैसे डीबीजीआरआईडी) को उनके डेटा जागरूकता प्रदान करती है। हालांकि, मैं इस स्पष्टीकरण को भी अस्वीकार करने के इच्छुक हूं, क्योंकि यह वर्ग ग्रिड से जुड़ा हुआ है, न कि डेटासेट, फिर से प्रभाव डेटासेट क्लास के साथ प्रतीत होता है।
जो मुझे मूल प्रश्न पर वापस लाता है। क्या यह टीडीएटीसेट क्लास, टीडीबीजीड का एक आर्टिफैक्ट, या कुछ और करने के लिए कुछ आंतरिक है?
मुझे यहां कुछ भी तनाव देने की अनुमति दें कि मैंने नीचे दी गई टिप्पणियों में से एक में जोड़ा है। किसी भी चीज़ से अधिक, मेरी पोस्ट डेवलपर्स को जागरूक करने के लिए डिज़ाइन की गई है कि जब वे डीबीजीआरआईड्स का उपयोग कर रहे हैं जिनके कॉलम ऑर्डर को बदला जा सकता है कि उनके टीएफआईल्ड का ऑर्डर भी बदल सकता है। यह आर्टिफैक्ट अस्थायी और गंभीर बग पेश कर सकता है जिसे पहचानना और ठीक करना बहुत मुश्किल हो सकता है। और, नहीं, मुझे नहीं लगता कि यह एक डेल्फी बग है। मुझे संदेह है कि सबकुछ काम कर रहा है क्योंकि इसे काम करने के लिए डिजाइन किया गया था। यह सिर्फ इतना है कि हम में से कई इस बात से अनजान थे कि यह व्यवहार हो रहा था। अब हम जानते हैं।
बहुत जानकारीपूर्ण है, लेकिन यहां कहीं कोई प्रश्न है? –
धन्यवाद @ कैरी, मुझे इसके बारे में कोई जानकारी नहीं है और मैं डेटासेट। फ़ील्ड [x] का निर्माण अक्सर कर रहा हूं। मुझे लगता है कि आपको इसे बग के रूप में Embarcadero वेबसाइट पर रिपोर्ट करनी चाहिए। – Wodzu
एक प्रश्न है, जो दूसरे वाक्य में दिखाई देता है: "क्या यह टीडीएटीसेट कक्षा में कुछ आंतरिक है, टीडीबीजीड का एक आर्टिफैक्ट, या कुछ और?"मैं कुछ समय (एक घंटा या तो) खर्च करता हूं जो टीसी कस्टमग्रिड और टीडीटासेट स्रोत दोनों को खोजता है, लेकिन यह नहीं देखा कि यह कहां हो रहा है। अधिक महत्वपूर्ण बात है, और यही कारण है कि मेरी पोस्ट इतनी लंबी है, मैं कम से कम बनाना चाहता था डेल्फी डेवलपर्स इस रोचक व्यवहार से अवगत हैं। किसी भी व्यक्ति जो डीबीजीड का उपयोग कर रहा है, या कुछ अन्य समान ग्रिड जो टीएफआईल्ड्स ऑर्डर में इन परिवर्तनों का उत्पादन करता है, यह एक अंतराल का स्रोत हो सकता है, और बग खोजने में मुश्किल हो सकती है। –