<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://www.dotnetzone.gr:443/cs/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="el"><title type="html">JA JA JA Blogging</title><subtitle type="html" /><id>https://www.dotnetzone.gr:443/cs/blogs/jajaja/atom.aspx</id><link rel="alternate" type="text/html" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/default.aspx" /><link rel="self" type="application/atom+xml" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/atom.aspx" /><generator uri="http://communityserver.org" version="2.1.20423.1">Community Server</generator><updated>2008-11-05T20:42:00Z</updated><entry><title>Report Localizer Ver. 0.5</title><link rel="alternate" type="text/html" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/2009/05/05/report-localizer-ver-0-5.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="599939" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/attachment/50482.ashx" /><id>https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/2009/05/05/report-localizer-ver-0-5.aspx</id><published>2009-05-06T00:43:00Z</published><updated>2009-05-06T00:43:00Z</updated><content type="html">&lt;P&gt;My programs are mainly client Windows Forms programs, aiming at the Greek market. Recently i decided to “globalize” my applications in an effort to expand my activities. Everything went quite smoothly until i tried to localize reports. I was frustrated because apparently there is no easy way to accomplish that. Well, to be honest, i localized some reports in the past and i used parameters to do it. But in that project the number of reports was small, less than ten, so i went for it without much thought. When you have to translate more than 120 reports, you start looking for more efficient ways. So, my quest begun.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What is out there…&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Perhaps the most complete and generic solution is described in &lt;A href="http://www.codeproject.com/KB/aspnet/RDLC_Localization.aspx"&gt;this&lt;/A&gt; article. The whole idea is to take advantage of some undocumented properties of the report components, like &lt;EM&gt;ValueLocID&lt;/EM&gt;, &lt;EM&gt;ToolTipLocID&lt;/EM&gt;, and &lt;EM&gt;LabelLocID&lt;/EM&gt;. Those are localization identifiers apparently not used by any service or the ReportViewer control. Yet, this solution made me rather skeptical, because there is no guarantee that this will continue to be the case in the future. Another report localization technique comes from &lt;A href="http://blogs.msdn.com/bwelcker/archive/2007/07/11/laser-guided-missiles-report-localization-through-parameters.aspx"&gt;this&lt;/A&gt; source. It doesn’t use the &lt;EM&gt;LocIDs&lt;/EM&gt; properties and the translated values are stored in the database rather than in resource files. Finally, one can use the &lt;A href="http://rdlclocalizer.codeplex.com/"&gt;RDLC Localizing Helper Class&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Report Localizer&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;After examining the available alternatives i decided to give a chance to the “Parameters” approach but a visual tool was needed to ease the entire process. I like using visual tools, especially when they are good and free! My favorites are &lt;A href="http://www.papadi.gr/resex.aspx"&gt;ResEx&lt;/A&gt; and the &lt;A href="http://www.codeplex.com/ResourceRefactoring"&gt;Resource Refactoring Tool&lt;/A&gt;. Despite my efforts, i was unable to find anything similar for translating reports. If there is something and i am not mentioning it here, i apologize in advance and i would appreciate it if you would bring it to my knowledge.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Report Localizer&lt;/EM&gt; is a first attempt to create such a tool. The idea is to deal directly with the &lt;STRONG&gt;rdlc&lt;/STRONG&gt; file itself. The first step is to identify those textbox elements that don’t hold expression values. The next step is to generate report parameters, of type string, that will be used to store the localized text version of table headers and other textbox items. Those parameters will be added directly to the &amp;lt;ReportParameters&amp;gt; section of the &lt;STRONG&gt;rdlc&lt;/STRONG&gt; file. At the same time, the original text in those textboxes will be replaced by an expression that emits the appropriate parameter value. Next, the new report file will be saved and added to the project, replacing the original. Finally, &lt;EM&gt;Report Localizer&lt;/EM&gt; will generate the necessary c# or vb code for calling the &lt;STRONG&gt;SetParameters()&lt;/STRONG&gt; method. When all those steps are completed, &lt;STRONG&gt;Resource Refactoring Tool&lt;/STRONG&gt; can be used to &lt;STRONG&gt;export&lt;/STRONG&gt; the hard coded strings to a &lt;STRONG&gt;resource file&lt;/STRONG&gt; and the &lt;STRONG&gt;ResEx&lt;/STRONG&gt; tool to &lt;STRONG&gt;add new locales and translate the string values&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Description of the application and a few screens&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Report Localizer&lt;/EM&gt; is a very basic tool. It has has no complex screens, it doesn’t expose many options and it’s &lt;STRONG&gt;not&lt;/STRONG&gt; complete yet. Thus the “0.5” of the version number. At the end of this post I will discuss about what can and what cannot be done with it and the type of functionality that needs to be implemented in future releases. Now, let me describe the features of the program.&lt;/P&gt;
&lt;P&gt;The user loads an existing &lt;STRONG&gt;rdlc&lt;/STRONG&gt; document by selecting the “Open” option in the “File” menu. The xml document is displayed in an WebBrowser control but the content can’t be edited directly by the user. When the document loads for the first time, &lt;EM&gt;Report Localizer&lt;/EM&gt; identifies the TextBoxes that serve as column headers or text labels and adds their definition into a “GoTo” drop down list. The user can navigate through that list to the TextBoxes. Of course, the user can navigate through out the entire document using the “Find/Search” capabilities of the application.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.dotnetzone.gr/cs/blogs/jajaja/MainScreen_4928EB69.jpg"&gt;&lt;IMG style="BORDER-BOTTOM:0px;BORDER-LEFT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;" title="Main Screen" border=0 alt="Main Screen" src="http://www.dotnetzone.gr/cs/blogs/jajaja/MainScreen_thumb_6DBD099E.jpg" width=892 height=474&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Defining and adding parameters is done very easily. All the user has to do is to select the option “Generate parameters” in the “Action” menu. Then, a new window appears in which two tables are displayed. The first table has four columns. The first column is the suggested parameter name, the second is the default value, the third is the prompt value and the fourth column exposes an option of whether this parameter should be generated. &lt;STRONG&gt;Always&lt;/STRONG&gt; use a prompt value, because if you don’t the parameter will be marked as internal and you won’t be able to access it through code. The second table lists the TextBox items that will be affected by the parameter generation. They may be more than one textboxes for the same parameter, if they happen to share the same text value.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.dotnetzone.gr/cs/blogs/jajaja/GenerateParameters_3193CEA7.jpg"&gt;&lt;IMG style="BORDER-BOTTOM:0px;BORDER-LEFT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;" title="Generate Parameters" border=0 alt="Generate Parameters" src="http://www.dotnetzone.gr/cs/blogs/jajaja/GenerateParameters_thumb_05E304AB.jpg" width=981 height=221&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;When the parameters are generated, use the drop down list to examine the value of the affected textboxes. Now the report file is ready to be saved. Since this is a very early version of the application, &lt;STRONG&gt;always&lt;/STRONG&gt; create a new file and keep the original for back up purposes. Now, the new file can be added to the project and the original report can be excluded. All that remains, is to generate the required c# or vb code. You can define which one of those parameters will be included in the code. This is done with the “Select parameters” option of the “Action” menu. You can make your selection in the new window that appears. Finally, use the appropriate “Generate code” menu command to get your code. This code has to be copied and pasted in to your form or in to your class.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.dotnetzone.gr/cs/blogs/jajaja/SelectParameters_1585A06D.jpg"&gt;&lt;IMG style="BORDER-BOTTOM:0px;BORDER-LEFT:0px;DISPLAY:inline;BORDER-TOP:0px;BORDER-RIGHT:0px;" title="Select Parameters" border=0 alt="Select Parameters" src="http://www.dotnetzone.gr/cs/blogs/jajaja/SelectParameters_thumb_5C029075.jpg" width=376 height=208&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Strengths and limitations&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Even with this early release a lot of things can be done. First of all, the &lt;EM&gt;Report Localizer&lt;/EM&gt; speeds up the process of parameter generation. Secondly, the code generation feature does its best to take off the burden of writing “dictation code” yourself; and we all know that “dictation code” is both boring and time consuming. But there are a few things you should bear in mind.&lt;/P&gt;
&lt;P&gt;The “suggested” parameter names are “generated” from the initial text values of the textboxes. So it’s best to use proper string values as names, when designing your report. If you don’t, you will have to do it in the stage of parameter generation. You should give the same attention when assigning the default values as well, because those values will be used by the program during code generation.&lt;/P&gt;
&lt;P&gt;One serious limitation of this release is that it doesn’t recognize subreports. This is a feature that needs to be implemented next. Why is that serious? Because, subreport parameter values cannot be set inside the &lt;STRONG&gt;SubreportProcessing&lt;/STRONG&gt; event handler. You can add a datasource to a subreport, but you cannot set the parameter values directly. In order to do that, you have to include them in the parent report, set their values there and finally pass those values to the subreport. The bottom line is that if you use subreports in your projects, an extra amount of work is needed to localize them with the “Parameter” approach. It’s not as tragic as it sounds, but it’s not a fully automated procedure at this stage.&lt;/P&gt;
&lt;P&gt;Finally, you cannot localize tooltip messages with this release. I didn’t include them because i never use them. I know that this sounds selfish, but i was trying to cover my own needs when i wrote &lt;EM&gt;Report Localizer&lt;/EM&gt;. I don’t use tooltips because in my opinion all text in a report must be well defined and self-describing. Reports are documents that eventually will be &lt;STRONG&gt;printed&lt;/STRONG&gt;. So, if there is something that requires further clarification, i always use a footnote. In future releases this feature could be added as well, but it’s of low priority.&lt;/P&gt;
&lt;P&gt;One last thing… Don’t forget about bugs!! Play safe and &lt;STRONG&gt;don’t overwrite&lt;/STRONG&gt; your original files with those created by the &lt;EM&gt;Report Localizer&lt;/EM&gt;. At least not with the current release.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The attachments…&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The first attachment is the &lt;STRONG&gt;msi&lt;/STRONG&gt; installer of the application. &lt;EM&gt;Report Localizer&lt;/EM&gt; can be used and distributed freely (reqs .NET 3.5). I would be more than happy if you decide to try my application and i would be twice as happy if you find it useful. I would also appreciate it if you report bug problems back to me or give any other feedback you might think is appropriate. There is also a second attachment which includes a small c# solution with localized reports (VS2008). The original reports are also included so that you can recreate the project yourself. I hope you find it useful as well.&lt;/P&gt;&lt;img src="https://www.dotnetzone.gr:443/cs/aggbug.aspx?PostID=50482" width="1" height="1"&gt;</content><author><name>Markos</name><uri>https://www.dotnetzone.gr:443/cs/members/Markos.aspx</uri></author></entry><entry><title>Hybrid Arithmetic Types. How to increase computational accuracy and range in a DIY approach.</title><link rel="alternate" type="text/html" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/2009/03/30/hybrid-arithmetic-types-how-to-increase-computational-accuracy-and-range-in-a-diy-approach.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="129845" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/attachment/49685.ashx" /><id>https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/2009/03/30/hybrid-arithmetic-types-how-to-increase-computational-accuracy-and-range-in-a-diy-approach.aspx</id><published>2009-03-30T08:08:00Z</published><updated>2009-03-30T08:08:00Z</updated><content type="html">&lt;P&gt;In the process of developing software that has to deal with complex numerical computations, many times you have to think of ways to manipulate your biggest enemy: the &lt;STRONG&gt;double&lt;/STRONG&gt; type. Some may disagree, but for a certain category of mathematical problems this type causes more trouble than convenience. Its accuracy may seem sufficient but it is inadequate. Round off errors accumulate and the final result is meaningless. Its range may seem large enough, but we quite often end up with an overflow or an underflow condition. What can be done then? Is there anything else to use in its place?&lt;/P&gt;
&lt;P&gt;The &lt;STRONG&gt;decimal&lt;/STRONG&gt; type seems to be a promising candidate. Well… it’s not!! Neither its numerical range is wider than that of the double type nor its accuracy is always exploitable. Suppose we have to multiply two numbers that differ greatly in their order of magnitude, for example 2 times srtq[2]e-25; the smaller one will be truncated to such an extent so that their product will be completely inaccurate. OK, the decimal type by itself can’t do much. But, what if it is combined with another type? Say, an &lt;STRONG&gt;int&lt;/STRONG&gt; or a &lt;STRONG&gt;long&lt;/STRONG&gt;?&lt;/P&gt;
&lt;P&gt;Decimal’s 28 digit accuracy makes it a perfect mantissa. The only other thing we need, is an integer exponent and this way we’ve just created our hybrid type (which is of course an object). The tricky part is to force the mantissa’s &lt;STRONG&gt;absolute&lt;/STRONG&gt;&amp;nbsp;&lt;STRONG&gt;value&lt;/STRONG&gt; to range between 1 (inclusive) and 10 (exclusive) or to be equal to 0. The next step is to define methods for addition, subtraction, multiplication and division or to overload the appropriate operators.&lt;/P&gt;
&lt;P&gt;The implementation is as easy as it sounds. The way to perform basic arithmetic operations is already &lt;A href="http://en.wikipedia.org/wiki/Floating_point"&gt;defined&lt;/A&gt; and well documented. For &lt;STRONG&gt;addition&lt;/STRONG&gt; and &lt;STRONG&gt;subtraction&lt;/STRONG&gt; we must first scale the exponents and then add or subtract the mantissae. &lt;STRONG&gt;Multiplication&lt;/STRONG&gt; and &lt;STRONG&gt;division&lt;/STRONG&gt; is much more straightforward since we only have to multiply (divide) mantissae and add (subtract) the exponents. When everything is finished we must scale the result so that we end up with a new hybrid type that will meet the specifications already mentioned in the previous paragraph.&lt;/P&gt;
&lt;P&gt;Are we done yet? Oh, NO!! We also need a library to calculate basic mathematical functions like Exp(x) and Sin(x), etc. The most straightforward approach to do this is to use &lt;A href="http://mathworld.wolfram.com/MaclaurinSeries.html"&gt;MacLaurin series&lt;/A&gt;. Surely, there are better and more efficient ways to achieve convergence, but for now MacLaurin series will do just fine.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The library&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;I have to confess that this is not the original implementation of the library. My first attempt was made a few years ago while i was learning C#. It had several drawbacks and very bad performance. The reason for this was that at the time i was experimenting with the string approach as well, in order to achieve “user-defined” floating point accuracy. Strings were involved a little more than they should be (a lot more actually) and because of that i didn’t use operator overloading. Anyway, at the time i had no idea where the code would lead me.&lt;/P&gt;
&lt;P&gt;This library is different. The code is a lot clearer and more readable. However, i cannot claim it is bug free. Should you find any bugs i would appreciate it a lot if you bring them to my attention. The object that makes all of the above possible is called &lt;STRONG&gt;HybridDecimal&lt;/STRONG&gt; and the class that is used to calculate basic mathematical functions is named &lt;STRONG&gt;HybridMath&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;Although HybridDecimal is an object, it has to behave like a numeric type. So a lot of overloading was needed to achieve that kind of behavior. It cooperates smoothly with other numeric types in almost every aspect, but assignment. For instance, you can write:&lt;/P&gt;
&lt;P&gt;HybridDecimal a = new HybridDecimal(1.3234, 234); a=a * 123;&lt;/P&gt;
&lt;P&gt;But you can’t write: a = 1; You should write a = (HybridDecimal)1; instead.&lt;/P&gt;
&lt;P&gt;Another aspect you should keep in mind is that HybridDecimal is a strange beast. The type of the exponent is long, so it is practically impossible to suffer from an overflow or underflow condition. I know that because i tested the original library extensively. Whenever a numerical procedure took a wrong path, it never exited. So in this implementation i had to add an &lt;EM&gt;OverflowExponent&lt;/EM&gt; property to simulate the overflow – underflow condition.&lt;/P&gt;
&lt;P&gt;Please try it and let me know of what you think.&lt;/P&gt;&lt;img src="https://www.dotnetzone.gr:443/cs/aggbug.aspx?PostID=49685" width="1" height="1"&gt;</content><author><name>Markos</name><uri>https://www.dotnetzone.gr:443/cs/members/Markos.aspx</uri></author></entry><entry><title>Μερικές σκέψεις πάνω στο θέμα της αποστολής Ιεραρχικών Μεταβολών (Hierarchical Changes) σε ADO.NET Databases</title><link rel="alternate" type="text/html" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/2008/11/05/hierarchical-changes-ado-net-databases.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="554290" href="https://www.dotnetzone.gr:443/cs/blogs/jajaja/attachment/46024.ashx" /><id>https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/2008/11/05/hierarchical-changes-ado-net-databases.aspx</id><published>2008-11-06T04:42:00Z</published><updated>2008-11-06T04:42:00Z</updated><content type="html">&amp;nbsp;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;B&gt;&lt;FONT size=4&gt;Εισαγωγή&lt;/FONT&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;Η ενημέρωση των μεταβολών που πραγματοποιούνται στα στοιχεία συνδεδεμένων πινάκων θεωρείται ως “&lt;/SPAN&gt;&lt;I&gt;advanced updating scenario&lt;/I&gt;”. &lt;SPAN&gt;Αδιαμφισβήτητα το &lt;/SPAN&gt;ADO.NET &lt;SPAN&gt;είναι μια σπουδαία τεχνολογία, αλλά όπως είναι ήδη γνωστό, ταλαιπωρεί τους χρήστες όσον αφορά την αποστολή και αποθήκευση &lt;/SPAN&gt;hierarchical data changes&lt;SPAN&gt;. Τα άρθρα και τα &lt;/SPAN&gt;videos&lt;SPAN&gt; που έχουν κατά καιρούς δημοσιευτεί σε διάφορα &lt;/SPAN&gt;blogs &lt;SPAN&gt;και &lt;/SPAN&gt;fora&lt;SPAN&gt;, δεν μου παρέχουν μία αίσθηση πληρότητας και θεωρώ ότι το θέμα δεν έχει καθόλου, μα καθόλου, εξαντληθεί.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;Ένας από τους λόγους που χρησιμοποιούνται οι βάσεις δεδομένων για την αποθήκευση της πληροφορίας, είναι η δυνατότητα διασύνδεσης των πινάκων για τη διατήρηση της σχεσιακής ακεραιότητας (&lt;/SPAN&gt;referential integrity) &lt;SPAN&gt;των εγγραφών. Έτσι, λοιπόν, πιστεύω ότι δικαιούμαι να ζητάω από το &lt;/SPAN&gt;ADO.NET &lt;SPAN&gt;πιο αποτελεσματική διαχείριση της πολυπλοκότητας της αποστολής των &lt;/SPAN&gt;hierarchical changes &lt;SPAN&gt;προς τη βάση, ελαχιστοποιώντας την παρέμβαση του &lt;/SPAN&gt;developer.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;Το παρόν &lt;/SPAN&gt;post &lt;SPAN&gt;φιλοδοξεί να επαναφέρει στο προσκήνιο ένα θέμα που φαίνεται να έχει ξεχαστεί λίγο και να δώσει το έναυσμα για νέες τοποθετήσεις και συζητήσεις. Όλα όσα πρόκειται ν' αναφερθούν, αφορούν στο &lt;/SPAN&gt;ADO.NET 2.0 &lt;SPAN&gt;και στο &lt;/SPAN&gt;Visual Studio 2005.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=4&gt;&lt;SPAN&gt;&lt;B&gt;Θεωρητική περιγραφή&lt;/B&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;Με βάση την τεχνολογία &lt;/SPAN&gt;ADO.NET &lt;SPAN&gt;η επιτυχής αποστολή και ενημέρωση των εγγραφών, όσον αφορά συνδεδεμένους πίνακες, σε μία βάση δεδομένων εξαρτάται από δύο παράγοντες: Ο ένας είναι η σειρά αποστολής των προσθηκών, μεταβολών και διαγραφών και ο άλλος είναι το &lt;/SPAN&gt;SourceVersion &lt;SPAN&gt;των παραμέτρων στα &lt;/SPAN&gt;Insert-, Update- &lt;SPAN&gt;και &lt;/SPAN&gt;Delete&lt;SPAN&gt;-&lt;/SPAN&gt; Commands &lt;SPAN&gt;των &lt;/SPAN&gt;DataAdapters.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;Όταν έχουμε συνδεδεμένους πίνακες (&lt;/SPAN&gt;parent – child relationship), &lt;SPAN&gt;με &lt;/SPAN&gt;&lt;B&gt;cascade actions&lt;/B&gt; &lt;SPAN&gt;για &lt;/SPAN&gt;&lt;B&gt;update &amp;amp;&lt;/B&gt;&lt;SPAN&gt;&lt;B&gt; &lt;/B&gt;&lt;/SPAN&gt;&lt;B&gt;delete&lt;/B&gt;, &lt;SPAN&gt;τόσο στη &lt;/SPAN&gt;&lt;SPAN&gt;&lt;B&gt;Βάση&lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt; όσο και στο &lt;/SPAN&gt;&lt;B&gt;DataSet&lt;/B&gt;, &lt;SPAN&gt;το &lt;/SPAN&gt;SourceVersion &lt;SPAN&gt;των παραμέτρων&lt;/SPAN&gt; &lt;SPAN&gt;παίζει καθοριστικό ρόλο. Οι περισσότεροι πιστεύω ότι κάνουμε χρήση του &lt;/SPAN&gt;DataSource Wizard &lt;SPAN&gt;για να προσθέσουμε πίνακες στον &lt;/SPAN&gt;DataSet Designer. &lt;SPAN&gt;Για το λόγο αυτό, ας εξετάσουμε πρώτα τι συμβαίνει με τους &lt;/SPAN&gt;TableAdapters &lt;SPAN&gt;που δημιουργεί ο &lt;/SPAN&gt;Wizard &lt;SPAN&gt;μόλις προσθέσει τους πίνακες στον &lt;/SPAN&gt;Designer.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;Ο &lt;/SPAN&gt;Wizard &lt;SPAN&gt;δημιουργεί τα &lt;/SPAN&gt;Select-, Delete-, Insert- &lt;SPAN&gt;και &lt;/SPAN&gt;Update- Commands &lt;SPAN&gt;τα οποία είναι υπεύθυνα για την ανάγνωση των δεδομένων από τη βάση, αλλά και την επιτυχημένη αποστολή των μεταβολών των εγγραφών που επεξεργάζεται ο χρήστης. Σ' αυτά τα &lt;/SPAN&gt;Commands &lt;SPAN&gt;υπάρχουν παράμετροι. Οι παράμετροι αυτοί έχουν, συνήθως, το ίδιο όνομα με τα πεδία του πίνακα (βεβαίως, προηγείται πάντοτε ο χαρακτήρας @). Το ενδιαφέρον, τώρα, πρέπει να εστιαστεί σ' εκείνες τις παραμέτρους που έχουν πρόθεμα @&lt;/SPAN&gt;Original_ &lt;SPAN&gt;και οι οποίες συναντώνται μόνο στα &lt;/SPAN&gt;Delete- &lt;SPAN&gt;και &lt;/SPAN&gt;Update- Commands. &lt;SPAN&gt;Κάπου εδώ τώρα, αρχίζει και γίνεται σημαντική η τιμή του &lt;/SPAN&gt;SourceVersion &lt;SPAN&gt;αυτών των παραμέτρων.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Όταν αλλάζει η τιμή των πεδίων των &lt;SPAN&gt;&lt;B&gt;primary keys&lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt; &lt;/SPAN&gt;στο &lt;SPAN&gt;parent table, &lt;/SPAN&gt;αυτές οι αλλαγές γίνονται &lt;SPAN&gt;cascade &lt;/SPAN&gt;στο &lt;SPAN&gt;child table (&lt;/SPAN&gt;αναφέρομαι στο &lt;SPAN&gt;DataSet). &lt;/SPAN&gt;Συνεπώς, όταν αποθηκεύσουμε αυτές της αλλαγές, εξαιτίας του &lt;SPAN&gt;cascade &lt;/SPAN&gt;που προκαλεί η αλλαγή των τιμών των πεδίων στο &lt;SPAN&gt;parent&lt;/SPAN&gt;&lt;SPAN&gt;&lt;B&gt; &lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;table&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN&gt;&lt;B&gt; &lt;/B&gt;&lt;/SPAN&gt;&lt;B&gt;της βάσης&lt;/B&gt;, οι αλλαγές αυτές προωθούνται &lt;B&gt;και&lt;/B&gt; στο &lt;SPAN&gt;child table &lt;/SPAN&gt;&lt;B&gt;της βάσης&lt;/B&gt;&lt;SPAN&gt;&lt;B&gt;.&lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt; &lt;/SPAN&gt;Άρα, στο &lt;SPAN&gt;&lt;B&gt;child &lt;/B&gt;&lt;/SPAN&gt;&lt;B&gt;του &lt;/B&gt;&lt;SPAN&gt;&lt;B&gt;DataSet&lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt; &lt;/SPAN&gt;οι &lt;SPAN&gt;original &lt;/SPAN&gt;τιμές των πεδίων του &lt;SPAN&gt;relation&lt;/SPAN&gt; &lt;B&gt;δε συμφωνούν&lt;/B&gt; με τις αντίστοιχες τιμές που έχει το &lt;SPAN&gt;child table &lt;/SPAN&gt;&lt;B&gt;στη βάση &lt;/B&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;ύστερα από την αποθήκευση των μεταβολών στο &lt;/SPAN&gt;&lt;SPAN&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;parent&lt;/SPAN&gt;&lt;/SPAN&gt;. Όταν, λοιπόν, προσπαθήσουμε να αποθηκεύσουμε τις αλλαγές του &lt;SPAN&gt;child &lt;/SPAN&gt;από το &lt;SPAN&gt;DataSet &lt;/SPAN&gt;στη βάση, θα πάρουμε ένα ωραιότατο &lt;SPAN&gt;exception.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;Για να το αποφύγουμε τη δυσάρεστη αυτή εξέλιξη, θα πρέπει το &lt;SPAN&gt;SourceVersion &lt;/SPAN&gt;των παραμέτρων των πεδίων του &lt;SPAN&gt;relation &lt;/SPAN&gt;στο &lt;SPAN&gt;child, &lt;/SPAN&gt;για το &lt;SPAN&gt;UpdateCommand, &lt;/SPAN&gt;να γίνει &lt;SPAN&gt;current. &lt;/SPAN&gt;Αυτό δεν ισχύει για τις παραμέτρους του &lt;SPAN&gt;DeleteCommand &lt;/SPAN&gt;μιας και οι διαγραφές αφορούν πάντα στις &lt;SPAN&gt;original &lt;/SPAN&gt;τιμές. Στον πίνακα 1 που ακολουθεί, παρατίθενται οι τιμές του &lt;SPAN&gt;SourceVersion&lt;/SPAN&gt; των παραμέτρων με πρόθεμα &lt;SPAN&gt;@Original_ &lt;/SPAN&gt;για το &lt;SPAN&gt;UpdateCommand &lt;/SPAN&gt;για συνδεδεμένους πίνακες&lt;SPAN&gt;. &lt;/SPAN&gt;Η λογική που αναπτύχθηκε στην παρούσα παράγραφο για δύο πίνακες επεκτείνεται σε &lt;SPAN&gt;n-&lt;/SPAN&gt;πίνακες.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;FONT size=2&gt;&lt;B&gt;Πίνακας 1.&lt;/B&gt; Τιμές που πρέπει να έχει το &lt;SPAN&gt;&lt;I&gt;SourceVersion&lt;/I&gt;&lt;/SPAN&gt;&lt;SPAN&gt; &lt;/SPAN&gt;των παραμέτρων με πρόθεμα @&lt;SPAN&gt;Original_ &lt;/SPAN&gt;του &lt;SPAN&gt;&lt;U&gt;UpdateCommand&lt;/U&gt;&lt;/SPAN&gt;&lt;SPAN&gt; &lt;/SPAN&gt;για επιτυχημένη αποστολή ιεραρχικών μεταβολών (&lt;SPAN&gt;hierarchical changes)&lt;/SPAN&gt; σε συνδεδεμένους πίνακες&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;





&lt;TABLE cellSpacing=0 cellPadding=4 width="100%" border=1&gt;






&lt;TR vAlign=top&gt;
&lt;TD width="16%"&gt;
&lt;P align=justify&gt;&lt;B&gt;Πίνακας&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="51%" colSpan=2&gt;
&lt;P align=center&gt;&lt;B&gt;Πεδία &lt;SPAN&gt;Primary Keys&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="33%"&gt;
&lt;P align=center&gt;&lt;B&gt;SourceVersion&lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD width="16%"&gt;
&lt;P align=justify&gt;Father&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="51%" colSpan=2&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;0&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="33%"&gt;
&lt;P align=center&gt;Original&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD width="16%" rowSpan=2&gt;
&lt;P align=justify&gt;Child(1)&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="14%" rowSpan=2&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;1&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;0&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;&lt;I&gt;Current&lt;/I&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;1'&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;Original&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD width="16%" rowSpan=2&gt;
&lt;P align=justify&gt;Child(2)&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="14%" rowSpan=2&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;2&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;&lt;SPAN style="BACKGROUND:none transparent scroll repeat 0% 0%;"&gt;1&lt;/SPAN&gt;&lt;/SUB&gt; = PK&lt;SUB&gt;0,1'&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;&lt;I&gt;Current&lt;/I&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;2'&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;Original&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD width="16%"&gt;
&lt;P align=left&gt;|&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="14%"&gt;
&lt;P align=center&gt;|&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;|&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;|&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD width="16%" rowSpan=2&gt;
&lt;P align=justify&gt;Child(n)&lt;/P&gt;&lt;/TD&gt;
&lt;TD width="14%" rowSpan=2&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;n&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;&lt;SPAN style="BACKGROUND:none transparent scroll repeat 0% 0%;"&gt;(n-1)&lt;/SPAN&gt;&lt;/SUB&gt; = PK&lt;SUB&gt;0,1',...,(n-1)'&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;&lt;I&gt;Current&lt;/I&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width="38%"&gt;
&lt;P align=center&gt;PK&lt;SUB&gt;n'&lt;/SUB&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=top width="33%"&gt;
&lt;P align=center&gt;Original&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;FONT size=2&gt;&lt;U&gt;Σημ.&lt;/U&gt;: Όπου PΚi&lt;SPAN&gt; &lt;/SPAN&gt;τα πεδία που αποτελούν το &lt;SPAN&gt;PK &lt;/SPAN&gt;του πίνακα&lt;SPAN&gt;-i, &lt;/SPAN&gt;και PΚi&lt;SPAN&gt;' &lt;/SPAN&gt;τα νέα πεδία του &lt;SPAN&gt;PK &lt;/SPAN&gt;του πίνακα&lt;SPAN&gt;-i &lt;/SPAN&gt;που προστίθενται σε εκείνα που 'κληρονομούνται' από το αμέσως προηγούμενο &lt;SPAN&gt;parent table.&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;Εντάξει με το &lt;SPAN&gt;SourceVersion &lt;/SPAN&gt;των &lt;SPAN&gt;UpdateCommands. &lt;/SPAN&gt;Με ποια σειρά, όμως, θα στείλουμε τις αλλαγές στη βάση; Για να απαντήσουμε σ' αυτό το ερώτημα θα χρησιμοποιήσουμε την “εις άτοπον απαγωγή”.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Ας εξετάσουμε τι θα συμβεί αν στείλουμε πρώτα τις προσθήκες. Υπάρχει περίπτωση αποτυχίας; Η απάντηση είναι ΝΑΙ! Αν κάπου στην ιεραρχία, δηλαδή σε κάποιο &lt;SPAN&gt;parent table, &lt;/SPAN&gt;αλλάξει η τιμή των πεδίων του &lt;SPAN&gt;PK &lt;/SPAN&gt;και στη συνέχεια προστεθούν εγγραφές στο &lt;SPAN&gt;child &lt;/SPAN&gt;(φυσικά, με τις νέες τιμές για το &lt;SPAN&gt;PK), &lt;/SPAN&gt;οι προσθήκες στο &lt;SPAN&gt;child&lt;/SPAN&gt; ΔΕ θα αποθηκευτούν γιατί οι νέες τιμές του &lt;SPAN&gt;PK &lt;/SPAN&gt;για το &lt;SPAN&gt;parent table &lt;/SPAN&gt;δεν υπάρχουν ακόμα στη βάση.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Ωραία, ας στείλουμε τότε πρώτα τις μεταβολές. ΕΝΣΤΑΣΗ! Κι εδώ μπορεί να υπάρξει αποτυχία. Αν μεταβάλουμε την τιμή των πεδίων του &lt;SPAN&gt;PK &lt;/SPAN&gt;στο &lt;SPAN&gt;parent &lt;/SPAN&gt;και στη συνέχεια διαγράψουμε εγγραφές στο &lt;SPAN&gt;child, &lt;/SPAN&gt;πως θα περάσουν οι διαγραφές στη βάση; Ας θυμηθούμε, το &lt;SPAN&gt;SourceVersion &lt;/SPAN&gt;των &lt;SPAN&gt;DeleteCommands&lt;/SPAN&gt; είναι &lt;SPAN&gt;original.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;B&gt;&lt;/B&gt;&lt;/SPAN&gt;&lt;B&gt;Ας ξεμπερδεύουμε, λοιπόν, πρώτα με τις διαγραφές&lt;/B&gt;. Έτσι, κι αλλιώς με &lt;SPAN&gt;SourceVersion original &lt;/SPAN&gt;δεν πρόκειται ν' αποτύχουμε. Καλά μέχρι εδώ, αλλά με ποια φορά θα ξεκινήσουμε να διαγράφουμε; Μα φυσικά, από το &lt;B&gt;τελευταίο&lt;/B&gt; &lt;SPAN&gt;child &lt;/SPAN&gt;προς το &lt;B&gt;αρχικό&lt;/B&gt; &lt;SPAN&gt;parent. &lt;/SPAN&gt;Δηλαδή:&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;B&gt;Φορά διαγραφών&lt;/B&gt;: &lt;SPAN&gt;Child(n) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Child(n-1) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; … &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Child(1) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Parent&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;Ωραία... Πάμε τώρα να κάνουμε τις προσθήκες. Πάλι ένσταση! Ο λόγος αποτυχίας κατά την αποστολή των προσθηκών εξακολουθεί να υφίσταται. &lt;B&gt;Άρα πρέπει να στείλουμε τις μεταβολές πριν τις προσθήκες&lt;/B&gt;. Με ποια φορά; Μα φυσικά αντίθετη από εκείνη με την οποία στείλαμε τις διαγραφές. Δηλαδή από το αρχικό &lt;SPAN&gt;parent &lt;/SPAN&gt;προς το τελευταίο &lt;SPAN&gt;child:&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;B&gt;Φορά μεταβολών&lt;/B&gt;:&lt;SPAN&gt; Parent &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN&gt;Child(1) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; … &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Child(n-1) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Child(n)&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;Για το τέλος, όπως είναι πια προφανές, μας έμειναν οι προσθήκες οι οποίες κι αυτές θα γίνουν με τη φορά που έγιναν και οι μεταβολές. Δηλαδή:&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;B&gt;Φορά προσθηκών&lt;/B&gt;:&lt;SPAN&gt; Parent &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN&gt;Child(1) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; … &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Child(n-1) &lt;/SPAN&gt;&lt;SPAN&gt;-&amp;gt;&lt;/SPAN&gt;&lt;SPAN&gt; Child(n)&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;Κάπου εδώ τελειώνει η θεωρητική περιγραφή. Για να δούμε, όμως, με ένα παράδειγμα πως υλοποιούνται όλα όσα περιγράφηκαν παραπάνω.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;FONT size=4&gt;&lt;B&gt;Από τη θεωρία στην πράξη&lt;/B&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Έφτασε, λοιπόν, η στιγμή της υλοποίησης ενός παραδείγματος το οποίο θα επιβεβαιώνει όλα όσα αναφέρθηκαν στην προηγούμενη ενότητα &lt;B&gt;και&lt;/B&gt; από πρακτικής απόψεως. Για να είναι πειστικό αυτό το παράδειγμα θα πρέπει να περιλαμβάνει τουλάχιστον τρεις πίνακες (&lt;SPAN&gt;father, child, grandchild). &lt;/SPAN&gt;Όχι ότι υπάρχει κάποια διαφορά σε σχέση με το συνηθισμένο &lt;SPAN&gt;master – detail, &lt;/SPAN&gt;αλλά έτσι για αλλαγή. &lt;SPAN&gt;&lt;/SPAN&gt;Επίσης, καλόν είναι και τα δεδομένα να έχουν μια δόση αληθοφάνειας, μιας και οι τεχνητές “υλοποιήσεις” συνήθως είναι βαρετές. &lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Το παράδειγμα που επέλεξα βασίζεται στην ταξινομική των ειδών με βάση το σύστημα του Λινναίου. Στο σύστημα αυτό όλα τα είδη έχουν ονοματεπώνυμο. Συνοπτικά, οι κύριες ταξινομικές βαθμίδες των ζωντανών οργανισμών είναι &lt;I&gt;Βασίλειο&lt;/I&gt; (πχ. Ζώα), &lt;I&gt;Φύλο&lt;/I&gt; (πχ. Αρθρόποδα), &lt;I&gt;Κλάση&lt;/I&gt; (πχ. Έντομα), &lt;I&gt;Τάξη&lt;/I&gt; (πχ. Δίπτερα), &lt;I&gt;Οικογένεια&lt;/I&gt; (πχ. &lt;SPAN&gt;Muscidae&lt;/SPAN&gt;), &lt;I&gt;Γένος&lt;/I&gt; (πχ. &lt;SPAN&gt;Musca) &lt;/SPAN&gt;και&lt;SPAN&gt; &lt;/SPAN&gt;&lt;I&gt;Είδος&lt;/I&gt; (πχ. &lt;SPAN&gt;&lt;I&gt;Musca domestica&lt;/I&gt;&lt;/SPAN&gt;&lt;SPAN&gt; – &lt;/SPAN&gt;οικιακή μύγα).&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Ας υποθέσουμε, λοιπόν, ότι θέλουμε να φτιάξουμε μια βάση δεδομένων για φυτικά είδη που μας ενδιαφέρουν και επιθυμούμε να ιεραρχήσουμε τα είδη αυτά βάσει της ταξινομικής τους κατάταξης. Στο παράδειγμά μας θα αδιαφορήσουμε για τις ανώτερες βαθμίδες και θα επικεντρωθούμε στις τρεις τελευταίες (οικογένεια, γένος και είδος). Αμέσως, αμέσως έχουμε τρεις πίνακες με φανερή σχέση &lt;SPAN&gt;father – child – grandchild. &lt;/SPAN&gt;Η βάση δεδομένων είναι απλή και τα &lt;SPAN&gt;relationships &lt;/SPAN&gt;ξεκάθαρα. Για περισσότερες πληροφορίες ρίξτε μια ματιά στο συνημμένο.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Δυστυχώς, παρόλο που η υλοποίηση φαντάζει &lt;SPAN&gt;straightforward, &lt;/SPAN&gt;το &lt;SPAN&gt;Visual Studio δ&lt;/SPAN&gt;ιαμαρτυρήθηκε(!?). Όταν επιχείρησα ν' αλλάξω το &lt;SPAN&gt;SourceVersion &lt;/SPAN&gt;των παραμέτρων με πρόθεμα &lt;SPAN&gt;@Original_ &lt;/SPAN&gt;στα &lt;SPAN&gt;UpdateCommands &lt;/SPAN&gt;των πινάκων των γενών και των ειδών από τον &lt;SPAN&gt;Designer, &lt;/SPAN&gt;σύμφωνα με τη θεωρητική περιγραφή, δε γινόταν &lt;SPAN&gt;build &lt;/SPAN&gt;το &lt;SPAN&gt;project. &lt;/SPAN&gt;Για κάποιο ανεξήγητο λόγο ο &lt;SPAN&gt;Wizard &lt;/SPAN&gt;δημιουργούσε μεθόδους &lt;SPAN&gt;Update &lt;/SPAN&gt;με λιγότερες παραμέτρους από εκείνες που πρέπει και το &lt;SPAN&gt;compilation &lt;/SPAN&gt;αποτύγχανε. Προς στιγμή, νόμισα ότι κάτι συμβαίνει με το &lt;SPAN&gt;CommandText &lt;/SPAN&gt;και γι' αυτό ζήτησα από το &lt;SPAN&gt;VS &lt;/SPAN&gt;να κάνει &lt;SPAN&gt;generate &lt;/SPAN&gt;τις αντίστοιχες &lt;SPAN&gt;Stored Procedures. &lt;/SPAN&gt;Όπως ήταν λογικό, το πρόβλημα δε διορθώθηκε. Η μαϊμουδιά της διαγραφής των προβληματικών μεθόδων απευθείας στον &lt;SPAN&gt;generated &lt;/SPAN&gt;κώδικα (μη φωνάζετε, ώρες – ώρες συμπεριφέρεται σα να το ζητάει ο οργανισμός του), κάνει &lt;SPAN&gt;compile&lt;/SPAN&gt;, αλλά πετάει &lt;SPAN&gt;concurrency violation exception &lt;/SPAN&gt;κατά την αποθήκευση των αλλαγών.&lt;SPAN&gt; Τ&lt;/SPAN&gt;ο γρήγορο &lt;SPAN&gt;fix, δ&lt;/SPAN&gt;εύτερη μαϊμουδιά, είναι να τεθεί στην &lt;SPAN&gt;ContinueUpdateOnError property &lt;/SPAN&gt;του &lt;SPAN&gt;DataAdapter &lt;/SPAN&gt;η&lt;SPAN&gt; &lt;/SPAN&gt;τιμή &lt;SPAN&gt;true &lt;/SPAN&gt;και το &lt;SPAN&gt;project &lt;/SPAN&gt;παίζει&lt;SPAN&gt;. &lt;/SPAN&gt;Δε ξέρω αν πρόκειται για κάποιο &lt;SPAN&gt;bug &lt;/SPAN&gt;του &lt;SPAN&gt;VS2005. &lt;/SPAN&gt;Θα ήταν, όμως, ενδιαφέρον εάν κάποιος αναγνώστης μπορεί να αναπαράγει το σφάλμα και να ενημερώσει για την ύπαρξή του. Ακόμη και εκείνοι που χρησιμοποιούν το &lt;SPAN&gt;VS2008 &lt;/SPAN&gt;ας ενημερώσουν για το αν&lt;SPAN&gt; ε&lt;/SPAN&gt;μφανίζεται αντίστοιχο πρόβλημα. Πάντως, δεν υπάρχει λόγος ανησυχίας μιας και όλα μπορούν να υλοποιηθούν με τρόπο ορθόδοξο, &lt;B&gt;χωρίς&lt;/B&gt; μαϊμουδιές.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Η λύση είναι απλή. Δεν πειράζουμε καθόλου την τιμή του &lt;SPAN&gt;SourceVersion &lt;/SPAN&gt;των παραμέτρων από τον &lt;SPAN&gt;Designer &lt;/SPAN&gt;και όλη τη δουλειά την κάνουμε προγραμματιστικά. Απλά, στο &lt;SPAN&gt;Load_Event &lt;/SPAN&gt;της φόρμας που εμφανίζει τα δεδομένα, φροντίζουμε να καλέσουμε τις αντίστοιχες μεθόδους για να αλλάξουμε το &lt;SPAN&gt;SourceVersion &lt;/SPAN&gt;(βλπ. κώδικα στο συνημμένο). Εκεί που χρησιμοποιώ &lt;SPAN&gt;methods &lt;/SPAN&gt;εσείς&lt;SPAN&gt; &lt;/SPAN&gt;χρησιμοποιήστε &lt;SPAN&gt;properties. &lt;/SPAN&gt;Δεν είναι όμορφο να περνά ένα και μοναδικό &lt;SPAN&gt;enum &lt;/SPAN&gt;σαν παράμετρος μιας μεθόδου. Ο κώδικας εμπεριέχει και κάποιο βασικό &lt;SPAN&gt;validation, &lt;/SPAN&gt;αλλά όχι σπουδαία πράγματα. Υπάρχει μόνο για να μην &lt;SPAN&gt;crash&lt;/SPAN&gt;-άρει η εφαρμογή. Παίξτε με τον κώδικα για να δείτε πως αντιδρά&lt;SPAN&gt; &lt;/SPAN&gt;σ' αυτές τις μεταβολές το &lt;SPAN&gt;DataSet &lt;/SPAN&gt;κατά την αποθήκευση.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;FONT style="FONT-SIZE:16pt;" size=4&gt;&lt;B&gt;Σχολιασμός&lt;/B&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Η υλοποίηση που περιγράφηκε στην προηγούμενη ενότητα δίνει αρκετό υλικό για σχολιασμό, κυρίως όσον αφορά στην ίδια την τεχνολογία του &lt;SPAN&gt;ADO.NET. &lt;/SPAN&gt;Ένα θέμα που με απασχολεί είναι το γεγονός ότι όταν γίνονται &lt;SPAN&gt;cascade &lt;/SPAN&gt;οι αλλαγές των πεδίων του &lt;SPAN&gt;PK&lt;/SPAN&gt; από το &lt;SPAN&gt;parent &lt;/SPAN&gt;στο &lt;SPAN&gt;child, &lt;/SPAN&gt;αλλάζει το &lt;SPAN&gt;RowVersion &lt;/SPAN&gt;των &lt;SPAN&gt;DataRows &lt;/SPAN&gt;στο &lt;SPAN&gt;child, &lt;/SPAN&gt;ακόμα κι αν δεν υπάρχουν αλλαγές στα δεδομένα (πέραν εκείνων που αφορούν στα πεδία του &lt;SPAN&gt;PK&lt;/SPAN&gt;). Αυτό έχει ως αποτέλεσμα να ζητάει το &lt;SPAN&gt;ADO.NET &lt;/SPAN&gt;να γίνουν &lt;SPAN&gt;update &lt;/SPAN&gt;στη βάση αλλαγές που ουσιαστικά δεν υπάρχουν και που η ίδια η βάση κάνει &lt;SPAN&gt;cascade &lt;/SPAN&gt;από μόνη της&lt;SPAN&gt; &lt;/SPAN&gt;από το &lt;SPAN&gt;parent &lt;/SPAN&gt;στο &lt;SPAN&gt;child&lt;/SPAN&gt;. Εύκολα υλοποιήσιμο &lt;SPAN&gt;workaround &lt;/SPAN&gt;δε φαίνεται να υπάρχει, καθώς η &lt;SPAN&gt;AcceptChanges() &lt;/SPAN&gt;αφορά σ' ολόκληρο το &lt;SPAN&gt;DataRow &lt;/SPAN&gt;και όχι σε μεμονωμένα πεδία. Συνεπώς, δε μπορεί να κληθεί αβασάνιστα, επειδή υπάρχει το ενδεχόμενο οι τιμές κάποιων πεδίων των &lt;SPAN&gt;child rows &lt;/SPAN&gt;να έχουν αλλάξει από το χρήστη.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Για τις διαγραφές είναι δυνατό να σκεφτεί κανείς ένα &lt;SPAN&gt;workaround. &lt;/SPAN&gt;Απλά καλούμε την &lt;SPAN&gt;AcceptChanges() &lt;/SPAN&gt;για διαγραφές που αφορούν σε &lt;SPAN&gt;children rows &lt;/SPAN&gt;που έγιναν &lt;SPAN&gt;cascade &lt;/SPAN&gt;όταν διαγράφηκε η &lt;SPAN&gt;parent row. &lt;/SPAN&gt;Απαιτείται, όμως, σωστός σχεδιασμός και προσεγμένη υλοποίηση, μιας και &lt;B&gt;αντιστρέφεται&lt;/B&gt; η σειρά αποστολής των διαγραφών στη βάση (από τα &lt;SPAN&gt;parents &lt;/SPAN&gt;πια,&lt;SPAN&gt; &lt;/SPAN&gt;στα &lt;SPAN&gt;children). &lt;/SPAN&gt;Επίσης, ιδιαίτερη μέριμνα πρέπει να ληφθεί για την περίπτωση αποτυχίας της διαγραφής του &lt;SPAN&gt;parent record.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&lt;SPAN&gt;&lt;/SPAN&gt;Υπάρχει, όμως, ακόμα ένα ζήτημα. Τελικά, πόσο επικίνδυνο είναι ο χρήστης να έχει πρόσβαση στις τιμές των &lt;SPAN&gt;PKs &lt;/SPAN&gt;σ' όλα τα επίπεδα της ιεραρχίας; Η απάντηση είναι ΠΟΛΥ ΕΠΙΚΙΝΔΥΝΟ! Ο κώδικας του παραδείγματος που είναι υπεύθυνος για την αποστολή των μεταβολών στη βάση μπορεί να χαρακτηριστεί ως &lt;B&gt;οδοστρωτήρας&lt;/B&gt;. Ακόμα κι αν οι τιμές των πεδίων των &lt;SPAN&gt;PKs &lt;/SPAN&gt;&lt;B&gt;είναι&lt;/B&gt; προστατευμένες, όπως στα walkthrough&lt;SPAN&gt;s &lt;/SPAN&gt;του &lt;SPAN&gt;MSDN&lt;/SPAN&gt;, αυτός ο ισοπεδωτικός τρόπος αποστολής των αλλαγών μπορεί να δημιουργήσει προβλήματα, εκτός κι αν αναφερόμαστε σε καθαρά &lt;SPAN&gt;&lt;B&gt;single user&lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt; &lt;/SPAN&gt;εφαρμογές.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Όταν θέλουμε ν' αποθηκεύσουμε αλλαγές σε &lt;SPAN&gt;relational data, &lt;/SPAN&gt;μάλλον πρέπει να σκεφτόμαστε με τη φιλοσοφία του &lt;SPAN&gt;object. &lt;/SPAN&gt;Αν στο παράδειγμά μας θεωρήσουμε ότι το βασικό &lt;SPAN&gt;object &lt;/SPAN&gt;είναι η οικογένεια, τότε για κάθε μία ξεχωριστά θα πρέπει να γίνει επιτυχημένη αποστολή των αλλαγών τόσο στην ίδια όσο και στα &lt;SPAN&gt;children &lt;/SPAN&gt;μέσω ενός &lt;SPAN&gt;&lt;B&gt;transaction&lt;/B&gt;&lt;/SPAN&gt;&lt;SPAN&gt;. &lt;/SPAN&gt;Αυτό σημαίνει ότι &lt;B&gt;για κάθε μία&lt;/B&gt; οικογένεια θα πρέπει να αποσταλούν με τη σωστή σειρά οι διαγραφές, οι μεταβολές και οι προσθήκες μέσω ενός &lt;SPAN&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;transaction &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;με &lt;/SPAN&gt;&lt;SPAN&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;scope &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-WEIGHT:normal;"&gt;τη συγκεκριμένη οικογένεια&lt;/SPAN&gt;&lt;SPAN&gt;. &lt;/SPAN&gt;Έτσι, λοιπόν, ή θα πετύχουν όλες οι μεταβολές ή καμία. Μετά μπορούμε να προχωρήσουμε στην επόμενη οικογένεια κλπ. Σ' αυτή την περίπτωση πρέπει να ληφθεί μέριμνα για την ενημέρωση του &lt;SPAN&gt;DataSet &lt;/SPAN&gt;όταν κάποιο(-α) &lt;SPAN&gt;transaction &lt;/SPAN&gt;αποτύχει. Το &lt;SPAN&gt;DataSet &lt;/SPAN&gt;είναι &lt;SPAN&gt;disconnected &lt;/SPAN&gt;και δε γνωρίζει τίποτε για το “φόνο” και πρέπει να ενημερωθεί για το &lt;SPAN&gt;rollback &lt;/SPAN&gt;των μεταβολών.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;Συγκεκριμένη υλοποίηση κώδικα που θα επιδεικνύει την παραπάνω προσέγγιση δεν έχω προς το παρόν να σας δώσω. Ελπίζω να βρήκατε ενδιαφέροντα τα όσα αναφέρονται στην παρούσα δημοσίευση και θα χαρώ πολύ να διαβάσω τις δικές σας σκέψεις και τοποθετήσεις, μιας και το θέμα των &lt;SPAN&gt;hierarchical updates &lt;/SPAN&gt;έχει πολλές ιδιαιτερότητες. Ζητώ προκαταβολικά συγνώμη για τα όποια λάθη και παραλείψεις μου.&lt;/P&gt;
&lt;P style="MARGIN-BOTTOM:0cm;LINE-HEIGHT:100%;" align=justify&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="https://www.dotnetzone.gr:443/cs/aggbug.aspx?PostID=46024" width="1" height="1"&gt;</content><author><name>Markos</name><uri>https://www.dotnetzone.gr:443/cs/members/Markos.aspx</uri></author><category term="ADO.NET 2.0" scheme="https://www.dotnetzone.gr:443/cs/blogs/jajaja/archive/tags/ADO.NET+2.0/default.aspx" /></entry></feed>