refactoring: Button, ImageButton and LinkButton are used insted internal DataControlB...
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / ObjectDataSourceView.cs
1 //
2 // System.Web.UI.WebControls.ObjectDataSourceView
3 //
4 // Authors:
5 //  Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2005 Novell, Inc. (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #if NET_2_0
32 using System;
33 using System.Reflection;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.ComponentModel;
37 using System.IO;
38 using System.Data;
39
40 namespace System.Web.UI.WebControls
41 {
42
43         public class ObjectDataSourceView : DataSourceView, IStateManager
44         {
45                 ObjectDataSource owner;
46                 HttpContext context;
47                 Type objectType;
48                 Type dataObjectType;
49                 
50                 StateBag viewState = new StateBag ();
51                 ParameterCollection selectParameters;
52                 ParameterCollection updateParameters;
53                 ParameterCollection deleteParameters;
54                 ParameterCollection insertParameters;
55                 ParameterCollection filterParameters;
56                 
57                 private static readonly object DeletedEvent = new object();
58                 private static readonly object DeletingEvent = new object();
59                 private static readonly object FilteringEvent = new object();
60                 private static readonly object InsertedEvent = new object();
61                 private static readonly object InsertingEvent = new object();
62                 private static readonly object ObjectCreatedEvent = new object();
63                 private static readonly object ObjectCreatingEvent = new object();
64                 private static readonly object ObjectDisposingEvent = new object();
65                 //              private static readonly object ResolvingMethodEvent = new object();
66                 private static readonly object SelectedEvent = new object();
67                 private static readonly object SelectingEvent = new object();
68                 private static readonly object UpdatedEvent = new object();
69                 private static readonly object UpdatingEvent = new object();
70                 
71                 public ObjectDataSourceView (ObjectDataSource owner, string name, HttpContext context): base (owner, name)
72                 {
73                         this.owner = owner;
74                         this.context = context;
75                 }
76                 
77                 public event ObjectDataSourceStatusEventHandler Deleted {
78                         add { Events.AddHandler (DeletedEvent, value); }
79                         remove { Events.RemoveHandler (DeletedEvent, value); }
80                 }
81                 
82                 public event ObjectDataSourceMethodEventHandler Deleting {
83                         add { Events.AddHandler (DeletingEvent, value); }
84                         remove { Events.RemoveHandler (DeletingEvent, value); }
85                 }
86                 
87                 public event ObjectDataSourceFilteringEventHandler Filtering {
88                         add { Events.AddHandler (FilteringEvent, value); }
89                         remove { Events.RemoveHandler (FilteringEvent, value); }
90                 }
91                 
92                 public event ObjectDataSourceStatusEventHandler Inserted {
93                         add { Events.AddHandler (InsertedEvent, value); }
94                         remove { Events.RemoveHandler (InsertedEvent, value); }
95                 }
96                 
97                 public event ObjectDataSourceMethodEventHandler Inserting {
98                         add { Events.AddHandler (InsertingEvent, value); }
99                         remove { Events.RemoveHandler (InsertingEvent, value); }
100                 }
101                 
102                 public event ObjectDataSourceObjectEventHandler ObjectCreated {
103                         add { Events.AddHandler (ObjectCreatedEvent, value); }
104                         remove { Events.RemoveHandler (ObjectCreatedEvent, value); }
105                 }
106                 
107                 public event ObjectDataSourceObjectEventHandler ObjectCreating {
108                         add { Events.AddHandler (ObjectCreatingEvent, value); }
109                         remove { Events.RemoveHandler (ObjectCreatingEvent, value); }
110                 }
111                 
112                 public event ObjectDataSourceDisposingEventHandler ObjectDisposing {
113                         add { Events.AddHandler (ObjectDisposingEvent, value); }
114                         remove { Events.RemoveHandler (ObjectDisposingEvent, value); }
115                 }
116                 
117                 /*              public event ObjectDataSourceResolvingMethodEventHandler ResolvingMethod {
118                                 add { Events.AddHandler (ResolvingMethodEvent, value); }
119                                 remove { Events.RemoveHandler (ResolvingMethodEvent, value); }
120                                 }
121                 */
122                 public event ObjectDataSourceStatusEventHandler Selected {
123                         add { Events.AddHandler (SelectedEvent, value); }
124                         remove { Events.RemoveHandler (SelectedEvent, value); }
125                 }
126                 
127                 public event ObjectDataSourceSelectingEventHandler Selecting {
128                         add { Events.AddHandler (SelectingEvent, value); }
129                         remove { Events.RemoveHandler (SelectingEvent, value); }
130                 }
131                 
132                 public event ObjectDataSourceStatusEventHandler Updated {
133                         add { Events.AddHandler (UpdatedEvent, value); }
134                         remove { Events.RemoveHandler (UpdatedEvent, value); }
135                 }
136                 
137                 public event ObjectDataSourceMethodEventHandler Updating {
138                         add { Events.AddHandler (UpdatingEvent, value); }
139                         remove { Events.RemoveHandler (UpdatingEvent, value); }
140                 }
141                 
142                 protected virtual void OnDeleted (ObjectDataSourceStatusEventArgs e)
143                 {
144                         if (Events != null) {
145                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [DeletedEvent];
146                                 if (eh != null) eh (this, e);
147                         }
148                 }
149                 
150                 protected virtual void OnDeleting (ObjectDataSourceMethodEventArgs e)
151                 {
152                         if (Events != null) {
153                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [DeletingEvent];
154                                 if (eh != null) eh (this, e);
155                         }
156                 }
157                 
158                 protected virtual void OnFiltering (ObjectDataSourceFilteringEventArgs e)
159                 {
160                         if (Events != null) {
161                                 ObjectDataSourceFilteringEventHandler eh = (ObjectDataSourceFilteringEventHandler) Events [FilteringEvent];
162                                 if (eh != null) eh (this, e);
163                         }
164                 }
165                 
166                 protected virtual void OnInserted (ObjectDataSourceStatusEventArgs e)
167                 {
168                         if (Events != null) {
169                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [InsertedEvent];
170                                 if (eh != null) eh (this, e);
171                         }
172                 }
173                 
174                 protected virtual void OnInserting (ObjectDataSourceMethodEventArgs e)
175                 {
176                         if (Events != null) {
177                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [InsertingEvent];
178                                 if (eh != null) eh (this, e);
179                         }
180                 }
181                 
182                 protected virtual void OnObjectCreated (ObjectDataSourceEventArgs e)
183                 {
184                         if (Events != null) {
185                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatedEvent];
186                                 if (eh != null) eh (this, e);
187                         }
188                 }
189                 
190                 protected virtual void OnObjectCreating (ObjectDataSourceEventArgs e)
191                 {
192                         if (Events != null) {
193                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatingEvent];
194                                 if (eh != null) eh (this, e);
195                         }
196                 }
197                 
198                 protected virtual void OnObjectDisposing (ObjectDataSourceDisposingEventArgs e)
199                 {
200                         if (Events != null) {
201                                 ObjectDataSourceDisposingEventHandler eh = (ObjectDataSourceDisposingEventHandler) Events [ObjectDisposingEvent];
202                                 if (eh != null) eh (this, e);
203                         }
204                 }
205                 
206                 /*              protected virtual void OnResolvingMethod (ObjectDataSourceResolvingMethodEventArgs e)
207                                 {
208                                 if (Events != null) {
209                                 ObjectDataSourceResolvingMethodEventHandler eh = (ObjectDataSourceResolvingMethodEventHandler) Events [ResolvingMethodEvent];
210                                 if (eh != null) eh (this, e);
211                                 }
212                                 }
213                 */
214                 
215                 protected virtual void OnSelected (ObjectDataSourceStatusEventArgs e)
216                 {
217                         if (Events != null) {
218                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [SelectedEvent];
219                                 if (eh != null) eh (this, e);
220                         }
221                 }
222                 
223                 protected virtual void OnSelecting (ObjectDataSourceSelectingEventArgs e)
224                 {
225                         if (Events != null) {
226                                 ObjectDataSourceSelectingEventHandler eh = (ObjectDataSourceSelectingEventHandler) Events [SelectingEvent];
227                                 if (eh != null) eh (this, e);
228                         }
229                 }
230                 
231                 protected virtual void OnUpdated (ObjectDataSourceStatusEventArgs e)
232                 {
233                         if (Events != null) {
234                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [UpdatedEvent];
235                                 if (eh != null) eh (this, e);
236                         }
237                 }
238                 
239                 protected virtual void OnUpdating (ObjectDataSourceMethodEventArgs e)
240                 {
241                         if (Events != null) {
242                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [UpdatingEvent];
243                                 if (eh != null) eh (this, e);
244                         }
245                 }
246                 
247                 StateBag ViewState {
248                         get { return viewState; }
249                 }
250                 
251                 public override bool CanDelete {
252                         get { return DeleteMethod.Length > 0; }
253                 }
254                 
255                 public override bool CanInsert {
256                         get { return InsertMethod.Length > 0; }
257                 }
258                 
259                 public override bool CanPage {
260                         get { return EnablePaging; }
261                 }
262                 
263                 public override bool CanRetrieveTotalRowCount {
264                         get { return SelectCountMethod.Length > 0; }
265                 }
266                 
267                 public override bool CanSort {
268                         get { return true; }
269                 }
270                 
271                 public override bool CanUpdate {
272                         get { return UpdateMethod.Length > 0; }
273                 }
274                 
275                 public ConflictOptions ConflictDetection {
276                         get {
277                                 object ret = ViewState ["ConflictDetection"];
278                                 return ret != null ? (ConflictOptions)ret : ConflictOptions.OverwriteChanges;
279                         }
280                         set {
281                                 ViewState ["ConflictDetection"] = value;
282                         }
283                 }
284                 
285                 public bool ConvertNullToDBNull {
286                         get {
287                                 object ret = ViewState ["ConvertNullToDBNull"];
288                                 return ret != null ? (bool)ret : false;
289                         }
290                         set {
291                                 ViewState ["ConvertNullToDBNull"] = value;
292                         }
293                 }
294                 
295                 public string DataObjectTypeName {
296                         get {
297                                 object ret = ViewState ["DataObjectTypeName"];
298                                 return ret != null ? (string)ret : string.Empty;
299                         }
300                         set {
301                                 ViewState ["DataObjectTypeName"] = value;
302                         }
303                 }
304                 
305                 public string DeleteMethod {
306                         get {
307                                 object ret = ViewState ["DeleteMethod"];
308                                 return ret != null ? (string)ret : string.Empty;
309                         }
310                         set {
311                                 ViewState ["DeleteMethod"] = value;
312                         }
313                 }
314                 
315                 public ParameterCollection DeleteParameters {
316                         get {
317                                 if (deleteParameters == null) {
318                                         deleteParameters = new ParameterCollection ();
319                                         deleteParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
320                                         if (IsTrackingViewState)
321                                                 ((IStateManager)deleteParameters).TrackViewState ();
322                                 }
323                                 return deleteParameters;
324                         }
325                 }
326                 
327                 public bool EnablePaging {
328                         get {
329                                 object ret = ViewState ["EnablePaging"];
330                                 return ret != null ? (bool)ret : false;
331                         }
332                         set {
333                                 ViewState ["EnablePaging"] = value;
334                         }
335                 }
336                 
337                 public string FilterExpression {
338                         get {
339                                 object ret = ViewState ["FilterExpression"];
340                                 return ret != null ? (string)ret : string.Empty;
341                         }
342                         set {
343                                 ViewState ["FilterExpression"] = value;
344                         }
345                 }
346                 
347                 public ParameterCollection FilterParameters {
348                         get {
349                                 if (filterParameters == null) {
350                                         filterParameters = new ParameterCollection ();
351                                         filterParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
352                                         if (IsTrackingViewState)
353                                                 ((IStateManager)filterParameters).TrackViewState ();
354                                 }
355                                 return filterParameters;
356                         }
357                 }
358                 
359                 public string InsertMethod {
360                         get {
361                                 object ret = ViewState ["InsertMethod"];
362                                 return ret != null ? (string)ret : string.Empty;
363                         }
364                         set {
365                                 ViewState ["InsertMethod"] = value;
366                         }
367                 }
368                 
369                 public ParameterCollection InsertParameters {
370                         get {
371                                 if (insertParameters == null) {
372                                         insertParameters = new ParameterCollection ();
373                                         insertParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
374                                         if (IsTrackingViewState)
375                                                 ((IStateManager)insertParameters).TrackViewState ();
376                                 }
377                                 return insertParameters;
378                         }
379                 }
380                 
381                 public string MaximumRowsParameterName {
382                         get {
383                                 object ret = ViewState ["MaximumRowsParameterName"];
384                                 return ret != null ? (string)ret : "maximumRows";
385                         }
386                         set {
387                                 ViewState ["MaximumRowsParameterName"] = value;
388                         }
389                 }
390                 
391                 [DefaultValueAttribute ("{0}")]
392                 public string OldValuesParameterFormatString {
393                         get {
394                                 object ret = ViewState ["OldValuesParameterFormatString"];
395                                 return ret != null ? (string)ret : "{0}";
396                         }
397                         set {
398                                 ViewState ["OldValuesParameterFormatString"] = value;
399                         }
400                 }
401                                 
402                 public string SelectCountMethod {
403                         get {
404                                 object ret = ViewState ["SelectCountMethod"];
405                                 return ret != null ? (string)ret : string.Empty;
406                         }
407                         set {
408                                 ViewState ["SelectCountMethod"] = value;
409                         }
410                 }
411                 
412                 public string SelectMethod {
413                         get {
414                                 object ret = ViewState ["SelectMethod"];
415                                 return ret != null ? (string)ret : string.Empty;
416                         }
417                         set {
418                                 ViewState ["SelectMethod"] = value;
419                         }
420                 }
421                 
422                 public ParameterCollection SelectParameters {
423                         get {
424                                 if (selectParameters == null) {
425                                         selectParameters = new ParameterCollection ();
426                                         selectParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
427                                         if (IsTrackingViewState)
428                                                 ((IStateManager)selectParameters).TrackViewState ();
429                                 }
430                                 return selectParameters;
431                         }
432                 }
433                 
434                 public string SortParameterName {
435                         get {
436                                 object ret = ViewState ["SortParameterName"];
437                                 return ret != null ? (string)ret : string.Empty;
438                         }
439                         set {
440                                 ViewState ["SortParameterName"] = value;
441                         }
442                 }
443                 
444                 public string StartRowIndexParameterName {
445                         get {
446                                 object ret = ViewState ["StartRowIndexParameterName"];
447                                 return ret != null ? (string)ret : "startRowIndex";
448                         }
449                         set {
450                                 ViewState ["StartRowIndexParameterName"] = value;
451                         }
452                 }
453                 
454                 public string TypeName {
455                         get {
456                                 object ret = ViewState ["TypeName"];
457                                 return ret != null ? (string)ret : string.Empty;
458                         }
459                         set {
460                                 ViewState ["TypeName"] = value;
461                                 objectType = null;
462                         }
463                 }
464                 
465                 public string UpdateMethod {
466                         get {
467                                 object ret = ViewState ["UpdateMethod"];
468                                 return ret != null ? (string)ret : string.Empty;
469                         }
470                         set {
471                                 ViewState ["UpdateMethod"] = value;
472                         }
473                 }
474                 
475                 public ParameterCollection UpdateParameters {
476                         get {
477                                 if (updateParameters == null) {
478                                         updateParameters = new ParameterCollection ();
479                                         updateParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
480                                         if (IsTrackingViewState)
481                                                 ((IStateManager)updateParameters).TrackViewState ();
482                                 }
483                                 return updateParameters;
484                         }
485                 }
486                 
487                 Type ObjectType {
488                         get {
489                                 if (objectType == null) {
490                                         objectType = Type.GetType (TypeName);
491                                         if (objectType == null)
492                                                 throw new InvalidOperationException ("Type not found: " + TypeName);
493                                 }
494                                 return objectType;
495                         }
496                 }
497                 
498                 Type DataObjectType {
499                         get {
500                                 if (dataObjectType == null) {
501                                         dataObjectType = Type.GetType (DataObjectTypeName);
502                                         if (objectType == null)
503                                                 throw new InvalidOperationException ("Type not found: " + DataObjectTypeName);
504                                 }
505                                 return dataObjectType;
506                         }
507                 }
508                 
509                 public IEnumerable Select (DataSourceSelectArguments arguments)
510                 {
511                         return ExecuteSelect (arguments);
512                 }
513                 
514                 public int Update (IDictionary keys, IDictionary values, IDictionary oldValues)
515                 {
516                         return ExecuteUpdate (keys, values, oldValues);
517                 }
518                 
519                 public int Delete (IDictionary keys, IDictionary oldValues)
520                 {
521                         return ExecuteDelete (keys, oldValues);
522                 }
523                 
524                 public int Insert (IDictionary values)
525                 {
526                         return ExecuteInsert (values);
527                 }
528                 
529                 protected override int ExecuteInsert (IDictionary values)
530                 {
531                         if (!CanInsert)
532                                 throw new NotSupportedException ("Insert operation not supported.");
533                                 
534                         IOrderedDictionary paramValues;
535                         MethodInfo method;
536                         
537                         if (DataObjectTypeName.Length == 0) {
538                                 paramValues = MergeParameterValues (InsertParameters, values, null, true);
539                                 method = GetObjectMethod (InsertMethod, paramValues);
540                         } else {
541                                 method = ResolveDataObjectMethod (InsertMethod, values, null, out paramValues);
542                         }
543                         
544                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
545                         OnInserting (args);
546                         if (args.Cancel)
547                                 return -1;
548                         
549                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
550                         OnInserted (rargs);
551                         
552                         if (rargs.Exception != null && !rargs.ExceptionHandled)
553                                 throw rargs.Exception;
554
555                         OnDataSourceViewChanged (EventArgs.Empty);
556
557                         return -1;
558                 }
559
560                 protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues)
561                 {
562                         if (!CanDelete)
563                                 throw new NotSupportedException ("Delete operation not supported.");
564                                 
565                         if (ConflictDetection == ConflictOptions.CompareAllValues && (oldValues == null || oldValues.Count == 0))
566                                 throw new InvalidOperationException ("ConflictDetection is set to CompareAllValues and oldValues collection is null or empty.");
567
568                         IDictionary oldDataValues;
569                         if (ConflictDetection == ConflictOptions.CompareAllValues) {
570                                 oldDataValues = new Hashtable ();
571                                 foreach (DictionaryEntry de in keys)
572                                         oldDataValues [de.Key] = de.Value;
573                                 foreach (DictionaryEntry de in oldValues)
574                                         oldDataValues [de.Key] = de.Value;
575                         } else
576                                 oldDataValues = keys;
577                                         
578                         IOrderedDictionary paramValues;
579                         MethodInfo method;
580                         
581                         if (DataObjectTypeName.Length == 0) {
582                                 paramValues = MergeParameterValues (DeleteParameters, null, oldDataValues, false);
583                                 method = GetObjectMethod (DeleteMethod, paramValues);
584                         } else {
585                                 method = ResolveDataObjectMethod (DeleteMethod, oldDataValues, null, out paramValues);
586                         }
587                         
588                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
589                         OnDeleting (args);
590                         if (args.Cancel)
591                                 return -1;
592                         
593                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
594                         
595                         OnDeleted (rargs);
596                         
597                         if (rargs.Exception != null && !rargs.ExceptionHandled)
598                                 throw rargs.Exception;
599
600                         OnDataSourceViewChanged (EventArgs.Empty);
601
602                         return -1;
603                 }
604                 
605                 protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues)
606                 {
607                         IOrderedDictionary paramValues;
608                         MethodInfo method;
609                         
610                         if (DataObjectTypeName.Length == 0)
611                         {
612                                 IDictionary dataValues;
613                                 IDictionary oldDataValues;
614                                 if (ConflictDetection == ConflictOptions.CompareAllValues) {
615                                         oldDataValues = new Hashtable ();
616                                         dataValues = values;
617                                         foreach (DictionaryEntry de in keys)
618                                                 oldDataValues [de.Key] = de.Value;
619                                         foreach (DictionaryEntry de in oldValues)
620                                                 oldDataValues [de.Key] = de.Value;
621                                 } else {
622                                         oldDataValues = keys;
623                                         dataValues = values;
624                                 }
625                                 paramValues = MergeParameterValues (UpdateParameters, dataValues, oldDataValues, false);
626                                 method = GetObjectMethod (UpdateMethod, paramValues);
627                         }
628                         else
629                         {
630                                 IDictionary dataValues = new Hashtable ();
631                                 IDictionary oldDataValues;
632                                 
633                                 foreach (DictionaryEntry de in values)
634                                         dataValues [de.Key] = de.Value;
635                                         
636                                 if (ConflictDetection == ConflictOptions.CompareAllValues) {
637                                         oldDataValues = new Hashtable ();
638                                         foreach (DictionaryEntry de in keys) {
639                                                 oldDataValues [de.Key] = de.Value;
640                                                 dataValues [de.Key] = de.Value;
641                                         }
642                                         foreach (DictionaryEntry de in oldValues)
643                                                 oldDataValues [de.Key] = de.Value;
644                                 } else {
645                                         oldDataValues = null;
646                                         foreach (DictionaryEntry de in keys)
647                                                 dataValues [de.Key] = de.Value;
648                                 }
649                                 method = ResolveDataObjectMethod (UpdateMethod, dataValues, oldDataValues, out paramValues);
650                         }                       
651
652                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
653                         OnUpdating (args);
654                         if (args.Cancel)
655                                 return -1;
656                         
657                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
658                         OnUpdated (rargs);
659                         
660                         if (rargs.Exception != null && !rargs.ExceptionHandled)
661                                 throw rargs.Exception;
662
663                         OnDataSourceViewChanged (EventArgs.Empty);
664
665                         return -1;
666                 }
667                 
668                 protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments)
669                 {
670                         arguments.RaiseUnsupportedCapabilitiesError (this);
671
672                         IOrderedDictionary paramValues = MergeParameterValues (SelectParameters, null, null, true);
673                         ObjectDataSourceSelectingEventArgs args = new ObjectDataSourceSelectingEventArgs (paramValues, arguments, false);
674                         OnSelecting (args);
675                         if (args.Cancel)
676                                 return new ArrayList ();
677                         
678                         if (CanRetrieveTotalRowCount && arguments.RetrieveTotalRowCount)
679                                 arguments.TotalRowCount = QueryTotalRowCount (paramValues, arguments);
680                         
681                         if (CanPage) {
682                                 if (StartRowIndexParameterName.Length == 0)
683                                         throw new InvalidOperationException ("Paging is enabled, but the StartRowIndexParameterName property is not set.");
684                                 if (MaximumRowsParameterName.Length == 0)
685                                         throw new InvalidOperationException ("Paging is enabled, but the MaximumRowsParameterName property is not set.");
686                                 paramValues [StartRowIndexParameterName] = arguments.StartRowIndex;
687                                 paramValues [MaximumRowsParameterName] = arguments.MaximumRows;
688                         }
689                         
690                         if (SortParameterName.Length > 0)
691                                 paramValues [SortParameterName] = arguments.SortExpression;
692                         
693                         object result = InvokeSelect (SelectMethod, paramValues);
694                         
695                         if (result is DataSet) {
696                                 DataSet dset = (DataSet) result;
697                                 if (dset.Tables.Count == 0)
698                                         throw new InvalidOperationException ("The select method returnet a DataSet which doesn't contain any table.");
699                                 result = dset.Tables [0];
700                         }
701                         
702                         if (result is DataTable) {
703                                 DataView dview = new DataView ((DataTable)result);
704                                 if (arguments.SortExpression != null && arguments.SortExpression.Length > 0) {
705                                         dview.Sort = arguments.SortExpression;
706                                 }
707                                 if (FilterExpression.Length > 0) {
708                                         IOrderedDictionary fparams = FilterParameters.GetValues (context, owner);
709                                         ObjectDataSourceFilteringEventArgs fargs = new ObjectDataSourceFilteringEventArgs (fparams);
710                                         OnFiltering (fargs);
711                                         if (!fargs.Cancel) {
712                                                 object[] formatValues = new object [fparams.Count];
713                                                 for (int n=0; n<formatValues.Length; n++) {
714                                                         formatValues [n] = fparams [n];
715                                                         if (formatValues [n] == null) return dview;
716                                                 }
717                                                 dview.RowFilter = string.Format (FilterExpression, formatValues);
718                                         }
719                                 }
720                                 return dview;
721                         }
722                         
723                         if (result is IEnumerable)
724                                 return (IEnumerable) result;
725                         else
726                                 return new object[] { result };
727                 }
728                 
729                 int QueryTotalRowCount (IOrderedDictionary mergedParameters, DataSourceSelectArguments arguments)
730                 {
731                         ObjectDataSourceSelectingEventArgs countArgs = new ObjectDataSourceSelectingEventArgs (mergedParameters, arguments, true);
732                         OnSelecting (countArgs);
733                         if (countArgs.Cancel)
734                                 return 0;
735                         
736                         object count = InvokeSelect (SelectCountMethod, mergedParameters);
737                         return (int) Convert.ChangeType (count, typeof(int));
738                 }
739                 
740                 object InvokeSelect (string methodName, IOrderedDictionary paramValues)
741                 {
742                         MethodInfo method = GetObjectMethod (methodName, paramValues);
743                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
744                         OnSelected (rargs);
745                         
746                         if (rargs.Exception != null && !rargs.ExceptionHandled)
747                                 throw rargs.Exception;
748
749                         return rargs.ReturnValue;
750                 }
751                 
752                 ObjectDataSourceStatusEventArgs InvokeMethod (MethodInfo method, IOrderedDictionary paramValues)
753                 {
754                         object instance = null;
755
756                         if (!method.IsStatic)
757                                 instance = CreateObjectInstance ();
758
759                         ParameterInfo[] pars = method.GetParameters ();
760                         
761                         ArrayList outParamInfos;
762                         object[] methodArgs = GetParameterArray (pars, paramValues, out outParamInfos); 
763                         
764                         if (methodArgs == null)
765                                 throw CreateMethodException (method.Name, paramValues);
766                                         
767                         object result = null;
768                         Hashtable outParams = null;
769                         
770                         try {
771                                 result = method.Invoke (instance, methodArgs);
772                                 if (outParamInfos != null) {
773                                         outParams = new Hashtable ();
774                                         foreach (ParameterInfo op in outParamInfos)
775                                                 outParams [op.Name] = methodArgs [op.Position - 1];
776                                 }
777                                 return new ObjectDataSourceStatusEventArgs (result, outParams, null);
778                         }
779                         catch (Exception ex) {
780                                 return new ObjectDataSourceStatusEventArgs (result, outParams, ex);
781                         }
782                         finally {
783                                 if (instance != null)
784                                         DisposeObjectInstance (instance);
785                         }
786                 }
787                 
788                 MethodInfo GetObjectMethod (string methodName, IOrderedDictionary parameters)
789                 {
790                         MemberInfo[] methods = ObjectType.GetMember (methodName);
791                         if (methods.Length > 1) {
792                                 // MSDN: The ObjectDataSource resolves method overloads by method name and number
793                                 // of parameters; the names and types of the parameters are not considered.
794                                 foreach (MemberInfo mi in methods) {
795                                         MethodInfo me = mi as MethodInfo;
796                                         if (me != null && me.GetParameters().Length == parameters.Count)
797                                                 return me;
798                                 }
799                         }
800                         else if (methods.Length == 1) {
801                                 MethodInfo me = methods[0] as MethodInfo;
802                                 if (me != null && me.GetParameters().Length == parameters.Count)
803                                         return me;
804                         }
805                         
806                         throw CreateMethodException (methodName, parameters);
807                 }
808                 
809                 MethodInfo ResolveDataObjectMethod (string methodName, IDictionary values, IDictionary oldValues, out IOrderedDictionary paramValues)
810                 {
811                         MethodInfo method;
812                         if (oldValues != null)
813                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType, DataObjectType });
814                         else
815                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType });
816                         
817                         if (method == null)
818                                 throw new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters of type '" + DataObjectType + "' in '" + ObjectType + "'.");
819                         
820                         paramValues = new OrderedDictionary ();
821                         ParameterInfo[] ps = method.GetParameters ();
822                         
823                         if (oldValues != null) {
824                                 if (FormatOldParameter (ps[0].Name) == ps[1].Name) {
825                                         paramValues [ps[0].Name] = CreateDataObject (values);
826                                         paramValues [ps[1].Name] = CreateDataObject (oldValues);
827                                 } else if (FormatOldParameter (ps[1].Name) == ps[0].Name) {
828                                         paramValues [ps[0].Name] = CreateDataObject (oldValues);
829                                         paramValues [ps[1].Name] = CreateDataObject (values);
830                                 } else
831                                         throw new InvalidOperationException ("Method '" + methodName + "' does not have any parameter that fits the value of OldValuesParameterFormatString.");  
832                         } else {
833                                 paramValues [ps[0].Name] = CreateDataObject (values);
834                         }
835                         return method;
836                 }
837                 
838                 Exception CreateMethodException (string methodName, IOrderedDictionary parameters)
839                 {
840                         string s = "";
841                         foreach (string p in parameters.Keys) {
842                                 s += p + ", ";
843                         }
844                         return new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters " + s + "in type '" + ObjectType + "'.");
845                 }
846                 
847                 object CreateDataObject (IDictionary values)
848                 {
849                         object ob = Activator.CreateInstance (DataObjectType);
850                         foreach (DictionaryEntry de in values) {
851                                 PropertyInfo p = DataObjectType.GetProperty ((string)de.Key);
852                                 if (p == null) throw new InvalidOperationException ("Property " + de.Key + " not found in type '" +DataObjectType + "'.");
853                                 p.SetValue (ob, ConvertParameter (p.PropertyType, de.Value), null);
854                         }
855                         return ob;
856                 }
857                 
858                 object CreateObjectInstance ()
859                 {
860                         ObjectDataSourceEventArgs args = new ObjectDataSourceEventArgs (null);
861                         OnObjectCreating (args);
862                         
863                         if (args.ObjectInstance != null)
864                                 return args.ObjectInstance;
865                                 
866                         object ob = Activator.CreateInstance (ObjectType);
867                         
868                         args.ObjectInstance = ob;
869                         OnObjectCreated (args);
870                         
871                         return args.ObjectInstance;
872                 }
873                 
874                 void DisposeObjectInstance (object obj)
875                 {
876                         ObjectDataSourceDisposingEventArgs args = new ObjectDataSourceDisposingEventArgs (obj);
877                         OnObjectDisposing (args);
878                         
879                         if (!args.Cancel) {
880                                 IDisposable disp = obj as IDisposable;
881                                 if (disp != null) disp.Dispose ();
882                         }
883                 }
884                 
885                 /// <summary>\r
886                 /// Merge the current data item fields with view parameter default values\r
887                 /// </summary>\r
888                 /// <param name="viewParams">default parameters</param>\r
889                 /// <param name="values">new parameters for update and insert</param>\r
890                 /// <param name="oldValues">old parameters for update and delete</param>\r
891                 /// <param name="allwaysAddNewValues">true for insert, as current item is\r
892                 /// irrelevant for insert</param>\r
893                 /// <returns>merged values</returns>
894                 IOrderedDictionary MergeParameterValues (ParameterCollection viewParams, IDictionary values, IDictionary oldValues, bool allwaysAddNewValues)
895                 {
896                         OrderedDictionary mergedValues = new OrderedDictionary ();
897                         foreach (Parameter p in viewParams) {
898                                 bool oldAdded = false;
899                                 if (oldValues != null && oldValues.Contains (p.Name)) {
900                                         object val = Convert.ChangeType (oldValues [p.Name], p.Type);
901                                         mergedValues [FormatOldParameter (p.Name)] = val;
902                                         oldAdded = true;
903                                 }
904                                 
905                                 if (values != null && values.Contains (p.Name)) {
906                                         object val = Convert.ChangeType (values [p.Name], p.Type);
907                                         mergedValues [p.Name] = val;
908                                 } else if (!oldAdded || allwaysAddNewValues) {
909                                         object val = p.GetValue (context, owner);
910                                         mergedValues [p.Name] = val;
911                                 }
912                         }
913                         
914                         if (values != null) {
915                                 foreach (DictionaryEntry de in values)
916                                         if (!mergedValues.Contains (de.Key))
917                                                 mergedValues [de.Key] = de.Value;
918                         }
919                         
920                         if (oldValues != null) {
921                                 foreach (DictionaryEntry de in oldValues)
922                                         if (!mergedValues.Contains (FormatOldParameter ((string)de.Key)))
923                                                 mergedValues [FormatOldParameter ((string)de.Key)] = de.Value;
924                         }
925                         
926                         return mergedValues;
927                 }
928                 
929                 object[] GetParameterArray (ParameterInfo[] methodParams, IOrderedDictionary viewParams, out ArrayList outParamInfos)
930                 {
931                         // FIXME: make this case insensitive
932
933                         outParamInfos = null;
934                         object[] values = new object [methodParams.Length];
935                         foreach (ParameterInfo mp in methodParams) {
936                         
937                                 // Parameter names must match
938                                 if (!viewParams.Contains (mp.Name)) return null;
939                                         
940                                 values [mp.Position] = ConvertParameter (mp.ParameterType, viewParams [mp.Name]);
941                                 if (mp.ParameterType.IsByRef) {
942                                         if (outParamInfos == null) outParamInfos = new ArrayList ();
943                                         outParamInfos.Add (mp);
944                                 }
945                         }
946                         return values;
947                 }
948                 
949                 object ConvertParameter (Type targetType, object value)
950                 {
951                         return ConvertParameter (Type.GetTypeCode (targetType), value);
952                 }
953                 
954                 object ConvertParameter (TypeCode targetType, object value)
955                 {
956                         if (value == null) {
957                                 if (targetType != TypeCode.Object && targetType != TypeCode.String)
958                                         value = 0;
959                                 else if (targetType == TypeCode.Object && ConvertNullToDBNull)
960                                         return DBNull.Value;
961                         }
962                         if (targetType == TypeCode.Object)
963                                 return value;
964                         else
965                                 return Convert.ChangeType (value, targetType);
966                 }
967                 
968                 string FormatOldParameter (string name)
969                 {
970                         string f = OldValuesParameterFormatString;
971                         if (f.Length > 0)
972                                 return String.Format (f, name);
973                         else
974                                 return name;
975                 }
976                 
977                 void OnParametersChanged (object sender, EventArgs args)
978                 {
979                         OnDataSourceViewChanged (EventArgs.Empty);
980                 }
981                 
982                 protected virtual void LoadViewState (object savedState)
983                 {
984                         object[] state = (savedState == null) ? new object [6] : (object[]) savedState;
985                         viewState.LoadViewState (state[0]);
986                         ((IStateManager)SelectParameters).LoadViewState (state[1]); 
987                         ((IStateManager)UpdateParameters).LoadViewState (state[2]); 
988                         ((IStateManager)DeleteParameters).LoadViewState (state[3]); 
989                         ((IStateManager)InsertParameters).LoadViewState (state[4]); 
990                         ((IStateManager)FilterParameters).LoadViewState (state[5]); 
991                 }
992
993                 protected virtual object SaveViewState()
994                 {
995                         object[] state = new object [6];
996                         state [0] = viewState.SaveViewState ();
997                         
998                         if (selectParameters != null)
999                                 state [1] = ((IStateManager)selectParameters).SaveViewState ();
1000                         if (updateParameters != null)
1001                                 state [2] = ((IStateManager)updateParameters).SaveViewState ();
1002                         if (deleteParameters != null)
1003                                 state [3] = ((IStateManager)deleteParameters).SaveViewState ();
1004                         if (insertParameters != null)
1005                                 state [4] = ((IStateManager)insertParameters).SaveViewState ();
1006                         if (filterParameters != null)
1007                                 state [5] = ((IStateManager)filterParameters).SaveViewState ();
1008                         
1009                         foreach (object ob in state)
1010                                 if (ob != null) return state;
1011                         
1012                         return null;
1013                 }
1014                 
1015                 protected virtual void TrackViewState()
1016                 {
1017                         viewState.TrackViewState ();
1018                         if (selectParameters != null) ((IStateManager)selectParameters).TrackViewState ();
1019                         if (updateParameters != null) ((IStateManager)updateParameters).TrackViewState ();
1020                         if (deleteParameters != null) ((IStateManager)deleteParameters).TrackViewState ();
1021                         if (insertParameters != null) ((IStateManager)insertParameters).TrackViewState ();
1022                         if (filterParameters != null) ((IStateManager)filterParameters).TrackViewState ();
1023                 }
1024                 
1025                 protected bool IsTrackingViewState
1026                 {
1027                         get { return viewState.IsTrackingViewState; }
1028                 }
1029                 
1030                 
1031                 bool IStateManager.IsTrackingViewState
1032                 {
1033                         get { return IsTrackingViewState; }
1034                 }
1035                 
1036                 void IStateManager.TrackViewState()
1037                 {
1038                         TrackViewState ();
1039                 }
1040                 
1041                 void IStateManager.LoadViewState (object savedState)
1042                 {
1043                         LoadViewState (savedState);
1044                 }
1045
1046                 object IStateManager.SaveViewState()
1047                 {
1048                         return SaveViewState ();
1049                 }
1050         }
1051 }
1052 #endif
1053