merge -r 98047:98048
[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 using System.Web.Compilation;
40
41 namespace System.Web.UI.WebControls
42 {
43
44         public class ObjectDataSourceView : DataSourceView, IStateManager
45         {
46                 ObjectDataSource owner;
47                 HttpContext context;
48                 Type objectType;
49                 Type dataObjectType;
50
51                 bool convertNullToDBNull = false;
52                 bool enablePaging = false;
53                 string dataObjectTypeName = null;
54                 string filterExpression = null;
55                 string maximumRowsParameterName = null;
56                 string oldValuesParameterFormatString = null;
57                 string deleteMethod = null;
58                 string insertMethod = null;
59                 string selectCountMethod = null;
60                 string selectMethod = null;
61                 string sortParameterName = null;
62                 string startRowIndexParameterName = null;
63                 string typeName = null;
64                 string updateMethod = null;
65                 private static string privateBinPath = null;
66
67                 bool isTrackingViewState = false;
68                 ParameterCollection selectParameters;
69                 ParameterCollection updateParameters;
70                 ParameterCollection deleteParameters;
71                 ParameterCollection insertParameters;
72                 ParameterCollection filterParameters;
73                 
74                 private static readonly object DeletedEvent = new object();
75                 private static readonly object DeletingEvent = new object();
76                 private static readonly object FilteringEvent = new object();
77                 private static readonly object InsertedEvent = new object();
78                 private static readonly object InsertingEvent = new object();
79                 private static readonly object ObjectCreatedEvent = new object();
80                 private static readonly object ObjectCreatingEvent = new object();
81                 private static readonly object ObjectDisposingEvent = new object();
82                 //              private static readonly object ResolvingMethodEvent = new object();
83                 private static readonly object SelectedEvent = new object();
84                 private static readonly object SelectingEvent = new object();
85                 private static readonly object UpdatedEvent = new object();
86                 private static readonly object UpdatingEvent = new object();
87                 
88                 public ObjectDataSourceView (ObjectDataSource owner, string name, HttpContext context): base (owner, name)
89                 {
90                         this.owner = owner;
91                         this.context = context;
92                 }
93                 
94                 public event ObjectDataSourceStatusEventHandler Deleted {
95                         add { Events.AddHandler (DeletedEvent, value); }
96                         remove { Events.RemoveHandler (DeletedEvent, value); }
97                 }
98                 
99                 public event ObjectDataSourceMethodEventHandler Deleting {
100                         add { Events.AddHandler (DeletingEvent, value); }
101                         remove { Events.RemoveHandler (DeletingEvent, value); }
102                 }
103                 
104                 public event ObjectDataSourceFilteringEventHandler Filtering {
105                         add { Events.AddHandler (FilteringEvent, value); }
106                         remove { Events.RemoveHandler (FilteringEvent, value); }
107                 }
108                 
109                 public event ObjectDataSourceStatusEventHandler Inserted {
110                         add { Events.AddHandler (InsertedEvent, value); }
111                         remove { Events.RemoveHandler (InsertedEvent, value); }
112                 }
113                 
114                 public event ObjectDataSourceMethodEventHandler Inserting {
115                         add { Events.AddHandler (InsertingEvent, value); }
116                         remove { Events.RemoveHandler (InsertingEvent, value); }
117                 }
118                 
119                 public event ObjectDataSourceObjectEventHandler ObjectCreated {
120                         add { Events.AddHandler (ObjectCreatedEvent, value); }
121                         remove { Events.RemoveHandler (ObjectCreatedEvent, value); }
122                 }
123                 
124                 public event ObjectDataSourceObjectEventHandler ObjectCreating {
125                         add { Events.AddHandler (ObjectCreatingEvent, value); }
126                         remove { Events.RemoveHandler (ObjectCreatingEvent, value); }
127                 }
128                 
129                 public event ObjectDataSourceDisposingEventHandler ObjectDisposing {
130                         add { Events.AddHandler (ObjectDisposingEvent, value); }
131                         remove { Events.RemoveHandler (ObjectDisposingEvent, value); }
132                 }
133                 
134                 /*              public event ObjectDataSourceResolvingMethodEventHandler ResolvingMethod {
135                                 add { Events.AddHandler (ResolvingMethodEvent, value); }
136                                 remove { Events.RemoveHandler (ResolvingMethodEvent, value); }
137                                 }
138                 */
139                 public event ObjectDataSourceStatusEventHandler Selected {
140                         add { Events.AddHandler (SelectedEvent, value); }
141                         remove { Events.RemoveHandler (SelectedEvent, value); }
142                 }
143                 
144                 public event ObjectDataSourceSelectingEventHandler Selecting {
145                         add { Events.AddHandler (SelectingEvent, value); }
146                         remove { Events.RemoveHandler (SelectingEvent, value); }
147                 }
148                 
149                 public event ObjectDataSourceStatusEventHandler Updated {
150                         add { Events.AddHandler (UpdatedEvent, value); }
151                         remove { Events.RemoveHandler (UpdatedEvent, value); }
152                 }
153                 
154                 public event ObjectDataSourceMethodEventHandler Updating {
155                         add { Events.AddHandler (UpdatingEvent, value); }
156                         remove { Events.RemoveHandler (UpdatingEvent, value); }
157                 }
158                 
159                 protected virtual void OnDeleted (ObjectDataSourceStatusEventArgs e)
160                 {
161                         if (Events != null) {
162                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [DeletedEvent];
163                                 if (eh != null) eh (this, e);
164                         }
165                 }
166                 
167                 protected virtual void OnDeleting (ObjectDataSourceMethodEventArgs e)
168                 {
169                         if (Events != null) {
170                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [DeletingEvent];
171                                 if (eh != null) eh (this, e);
172                         }
173                 }
174                 
175                 protected virtual void OnFiltering (ObjectDataSourceFilteringEventArgs e)
176                 {
177                         if (Events != null) {
178                                 ObjectDataSourceFilteringEventHandler eh = (ObjectDataSourceFilteringEventHandler) Events [FilteringEvent];
179                                 if (eh != null) eh (this, e);
180                         }
181                 }
182                 
183                 protected virtual void OnInserted (ObjectDataSourceStatusEventArgs e)
184                 {
185                         if (Events != null) {
186                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [InsertedEvent];
187                                 if (eh != null) eh (this, e);
188                         }
189                 }
190                 
191                 protected virtual void OnInserting (ObjectDataSourceMethodEventArgs e)
192                 {
193                         if (Events != null) {
194                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [InsertingEvent];
195                                 if (eh != null) eh (this, e);
196                         }
197                 }
198                 
199                 protected virtual void OnObjectCreated (ObjectDataSourceEventArgs e)
200                 {
201                         if (Events != null) {
202                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatedEvent];
203                                 if (eh != null) eh (this, e);
204                         }
205                 }
206                 
207                 protected virtual void OnObjectCreating (ObjectDataSourceEventArgs e)
208                 {
209                         if (Events != null) {
210                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatingEvent];
211                                 if (eh != null) eh (this, e);
212                         }
213                 }
214                 
215                 protected virtual void OnObjectDisposing (ObjectDataSourceDisposingEventArgs e)
216                 {
217                         if (Events != null) {
218                                 ObjectDataSourceDisposingEventHandler eh = (ObjectDataSourceDisposingEventHandler) Events [ObjectDisposingEvent];
219                                 if (eh != null) eh (this, e);
220                         }
221                 }
222                 
223                 /*              protected virtual void OnResolvingMethod (ObjectDataSourceResolvingMethodEventArgs e)
224                                 {
225                                 if (Events != null) {
226                                 ObjectDataSourceResolvingMethodEventHandler eh = (ObjectDataSourceResolvingMethodEventHandler) Events [ResolvingMethodEvent];
227                                 if (eh != null) eh (this, e);
228                                 }
229                                 }
230                 */
231                 
232                 protected virtual void OnSelected (ObjectDataSourceStatusEventArgs e)
233                 {
234                         if (Events != null) {
235                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [SelectedEvent];
236                                 if (eh != null) eh (this, e);
237                         }
238                 }
239                 
240                 protected virtual void OnSelecting (ObjectDataSourceSelectingEventArgs e)
241                 {
242                         if (Events != null) {
243                                 ObjectDataSourceSelectingEventHandler eh = (ObjectDataSourceSelectingEventHandler) Events [SelectingEvent];
244                                 if (eh != null) eh (this, e);
245                         }
246                 }
247                 
248                 protected virtual void OnUpdated (ObjectDataSourceStatusEventArgs e)
249                 {
250                         if (Events != null) {
251                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [UpdatedEvent];
252                                 if (eh != null) eh (this, e);
253                         }
254                 }
255                 
256                 protected virtual void OnUpdating (ObjectDataSourceMethodEventArgs e)
257                 {
258                         if (Events != null) {
259                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [UpdatingEvent];
260                                 if (eh != null) eh (this, e);
261                         }
262                 }
263                 
264                 public override bool CanDelete {
265                         get { return DeleteMethod.Length > 0; }
266                 }
267                 
268                 public override bool CanInsert {
269                         get { return InsertMethod.Length > 0; }
270                 }
271                 
272                 public override bool CanPage {
273                         get { return EnablePaging; }
274                 }
275                 
276                 public override bool CanRetrieveTotalRowCount {
277                         get {
278                                 if( SelectCountMethod.Length > 0)
279                                         return true;
280
281                                 return !EnablePaging;
282                         }
283                 }
284                 
285                 public override bool CanSort {
286                         get { return true; }
287                 }
288                 
289                 public override bool CanUpdate {
290                         get { return UpdateMethod.Length > 0; }
291                 }
292
293                 // LAME SPEC: MSDN says value should be stored in ViewState but tests show otherwise.
294                 private ConflictOptions conflictDetection = ConflictOptions.OverwriteChanges;
295                 public ConflictOptions ConflictDetection {
296                         get { return conflictDetection; }
297                         set {\r
298                                 if (ConflictDetection == value)\r
299                                         return;
300                                 conflictDetection = value;\r
301                                 OnDataSourceViewChanged (EventArgs.Empty);
302                         }
303                 }
304
305                 public bool ConvertNullToDBNull {
306                         get { return convertNullToDBNull; }
307                         set { convertNullToDBNull = value; }
308                 }
309
310                 public string DataObjectTypeName {
311                         get {
312                                 return dataObjectTypeName != null ? dataObjectTypeName : string.Empty;
313                         }
314                         set {\r
315                                 if (DataObjectTypeName == value)\r
316                                         return;
317                                 dataObjectTypeName = value;
318                                 dataObjectType = null;\r
319                                 OnDataSourceViewChanged (EventArgs.Empty);
320                         }
321                 }
322
323                 public string DeleteMethod {
324                         get {
325                                 return deleteMethod != null ? deleteMethod : string.Empty;
326                         }
327                         set {
328                                 deleteMethod = value;
329                         }
330                 }
331                 
332                 public ParameterCollection DeleteParameters {
333                         get {
334                                 if (deleteParameters == null) {
335                                         deleteParameters = new ParameterCollection ();
336                                 }
337                                 return deleteParameters;
338                         }
339                 }
340
341                 public bool EnablePaging {
342                         get {
343                                 return enablePaging;
344                         }
345                         set {\r
346                                 if (EnablePaging == value)\r
347                                         return;
348                                 enablePaging = value;\r
349                                 OnDataSourceViewChanged (EventArgs.Empty);
350                         }
351                 }
352
353                 public string FilterExpression {
354                         get {
355                                 return filterExpression != null ? filterExpression : string.Empty;
356                         }
357                         set {\r
358                                 if (FilterExpression == value)\r
359                                         return;
360                                 filterExpression = value;\r
361                                 OnDataSourceViewChanged (EventArgs.Empty);
362                         }
363                 }
364
365                 public ParameterCollection FilterParameters {
366                         get {
367                                 if (filterParameters == null) {
368                                         filterParameters = new ParameterCollection ();
369                                         filterParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
370                                         if (IsTrackingViewState)
371                                                 ((IStateManager)filterParameters).TrackViewState ();
372                                 }
373                                 return filterParameters;
374                         }
375                 }
376
377                 public string InsertMethod {
378                         get {
379                                 return insertMethod != null ? insertMethod : string.Empty;
380                         }
381                         set {
382                                 insertMethod = value;
383                         }
384                 }
385
386                 public ParameterCollection InsertParameters {
387                         get {
388                                 if (insertParameters == null) {
389                                         insertParameters = new ParameterCollection ();
390                                 }
391                                 return insertParameters;
392                         }
393                 }
394
395                 public string MaximumRowsParameterName {
396                         get {
397                                 return maximumRowsParameterName != null ? maximumRowsParameterName : "maximumRows";
398                         }
399                         set {\r
400                                 if (MaximumRowsParameterName == value)\r
401                                         return;
402                                 maximumRowsParameterName = value;\r
403                                 OnDataSourceViewChanged (EventArgs.Empty);
404                         }
405                 }
406
407                 public string OldValuesParameterFormatString {
408                         get {
409                                 return oldValuesParameterFormatString != null ? oldValuesParameterFormatString : "{0}";
410                         }
411                         set {\r
412                                 if (OldValuesParameterFormatString == value)\r
413                                         return;
414                                 oldValuesParameterFormatString = value;\r
415                                 OnDataSourceViewChanged (EventArgs.Empty);
416                         }
417                 }
418
419                 public string SelectCountMethod {
420                         get {
421                                 return selectCountMethod != null ? selectCountMethod : string.Empty;
422                         }
423                         set {
424                                 if (SelectCountMethod == value)
425                                         return;
426                                 selectCountMethod = value;
427                                 OnDataSourceViewChanged (EventArgs.Empty);
428                         }
429                 }
430
431                 public string SelectMethod {
432                         get {
433                                 return selectMethod != null ? selectMethod : string.Empty;
434                         }
435                         set {
436                                 if (SelectMethod == value)
437                                         return;
438                                 selectMethod = value;
439                                 OnDataSourceViewChanged (EventArgs.Empty);
440                         }
441                 }
442
443                 public ParameterCollection SelectParameters {
444                         get {
445                                 if (selectParameters == null) {
446                                         selectParameters = new ParameterCollection ();
447                                         selectParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
448                                         if (IsTrackingViewState)
449                                                 ((IStateManager)selectParameters).TrackViewState ();
450                                 }
451                                 return selectParameters;
452                         }
453                 }
454
455                 public string SortParameterName {
456                         get {
457                                 return sortParameterName != null ? sortParameterName : string.Empty;
458                         }
459                         set {
460                                 sortParameterName = value;
461                         }
462                 }
463
464                 public string StartRowIndexParameterName {
465                         get {
466                                 return startRowIndexParameterName != null ? startRowIndexParameterName : "startRowIndex";
467                         }
468                         set {\r
469                                 if (StartRowIndexParameterName == value)\r
470                                         return;
471                                 startRowIndexParameterName = value;\r
472                                 OnDataSourceViewChanged (EventArgs.Empty);
473                         }
474                 }
475
476                 public string TypeName {
477                         get {
478                                 return typeName != null ? typeName : string.Empty;
479                         }
480                         set {\r
481                                 if (TypeName == value)\r
482                                         return;
483                                 typeName = value;
484                                 objectType = null;\r
485                                 OnDataSourceViewChanged (EventArgs.Empty);
486                         }
487                 }
488
489                 public string UpdateMethod {
490                         get {
491                                 return updateMethod != null ? updateMethod : string.Empty;
492                         }
493                         set {
494                                 updateMethod = value;
495                         }
496                 }
497
498                 public ParameterCollection UpdateParameters {
499                         get {
500                                 if (updateParameters == null) {
501                                         updateParameters = new ParameterCollection ();
502                                 }
503                                 return updateParameters;
504                         }
505                 }
506     
507                 Type ObjectType {
508                         get {
509                                 if (objectType == null) {
510                                         objectType = HttpApplication.LoadType (TypeName);
511                                         if (objectType == null)
512                                                 throw new InvalidOperationException ("Type not found: " + TypeName);
513                                 }
514                                 return objectType;
515                         }
516                 }
517                 
518                 Type DataObjectType {
519                         get {
520                                 if (dataObjectType == null) {
521                                         dataObjectType = HttpApplication.LoadType (DataObjectTypeName);
522                                         if (dataObjectType == null)
523                                                 throw new InvalidOperationException ("Type not found: " + DataObjectTypeName);
524                                 }
525                                 return dataObjectType;
526                         }
527                 }
528                 
529                 public IEnumerable Select (DataSourceSelectArguments arguments)
530                 {
531                         return ExecuteSelect (arguments);
532                 }
533                 
534                 public int Update (IDictionary keys, IDictionary values, IDictionary oldValues)
535                 {
536                         return ExecuteUpdate (keys, values, oldValues);
537                 }
538                 
539                 public int Delete (IDictionary keys, IDictionary oldValues)
540                 {
541                         return ExecuteDelete (keys, oldValues);
542                 }
543                 
544                 public int Insert (IDictionary values)
545                 {
546                         return ExecuteInsert (values);
547                 }
548                 
549                 protected override int ExecuteInsert (IDictionary values)
550                 {
551                         if (!CanInsert)
552                                 throw new NotSupportedException ("Insert operation not supported.");
553                                 
554                         IOrderedDictionary paramValues;
555                         MethodInfo method;
556                         
557                         if (DataObjectTypeName.Length == 0) {
558                                 paramValues = MergeParameterValues (InsertParameters, values, null);
559                                 method = GetObjectMethod (InsertMethod, paramValues, DataObjectMethodType.Insert);
560                         } else {
561                                 method = ResolveDataObjectMethod (InsertMethod, values, null, out paramValues);
562                         }
563                         
564                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
565                         OnInserting (args);
566                         if (args.Cancel)
567                                 return -1;
568                         
569                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
570                         OnInserted (rargs);
571                         
572                         if (rargs.Exception != null && !rargs.ExceptionHandled)
573                                 throw rargs.Exception;
574
575                         if (owner.EnableCaching)
576                                 owner.Cache.Expire ();
577                         
578                         OnDataSourceViewChanged (EventArgs.Empty);
579
580                         return -1;
581                 }
582
583                 protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues)
584                 {
585                         if (!CanDelete)
586                                 throw new NotSupportedException ("Delete operation not supported.");
587                                 
588                         if (ConflictDetection == ConflictOptions.CompareAllValues && (oldValues == null || oldValues.Count == 0))
589                                 throw new InvalidOperationException ("ConflictDetection is set to CompareAllValues and oldValues collection is null or empty.");
590
591                         IDictionary oldDataValues;
592                         oldDataValues = BuildOldValuesList (keys, oldValues, false);
593                                         
594                         IOrderedDictionary paramValues;
595                         MethodInfo method;
596                         
597                         if (DataObjectTypeName.Length == 0) {
598                                 paramValues = MergeParameterValues (DeleteParameters, null, oldDataValues);
599                                 method = GetObjectMethod (DeleteMethod, paramValues, DataObjectMethodType.Delete);
600                         } else {
601                                 method = ResolveDataObjectMethod (DeleteMethod, oldDataValues, null, out paramValues);
602                         }
603                         
604                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
605                         OnDeleting (args);
606                         if (args.Cancel)
607                                 return -1;
608                         
609                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
610                         
611                         OnDeleted (rargs);
612                         
613                         if (rargs.Exception != null && !rargs.ExceptionHandled)
614                                 throw rargs.Exception;
615
616                         if (owner.EnableCaching)
617                                 owner.Cache.Expire ();
618                         
619                         OnDataSourceViewChanged (EventArgs.Empty);
620
621                         return -1;
622                 }
623
624                 protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues)
625                 {
626                         IOrderedDictionary paramValues;
627                         MethodInfo method;
628
629                         IDictionary oldDataValues;
630                         oldDataValues = BuildOldValuesList (keys, oldValues, true);
631
632                         if (DataObjectTypeName.Length == 0)
633                         {
634                                 IDictionary dataValues;
635                                 dataValues = values;
636                                 paramValues = MergeParameterValues (UpdateParameters, dataValues, oldDataValues);
637                                 method = GetObjectMethod (UpdateMethod, paramValues, DataObjectMethodType.Update);
638                         }
639                         else
640                         {
641                                 if (ConflictDetection != ConflictOptions.CompareAllValues) {
642                                         oldDataValues = null;
643                                 }
644                                 IDictionary dataValues = new Hashtable ();
645                                 if (keys != null) {
646                                         foreach (DictionaryEntry de in keys)
647                                                 dataValues [de.Key] = de.Value;
648                                 }
649                                 if (values != null) {
650                                         foreach (DictionaryEntry de in values)
651                                                 dataValues [de.Key] = de.Value;
652                                 }
653
654                                 method = ResolveDataObjectMethod (UpdateMethod, dataValues, oldDataValues, out paramValues);
655                         }                       
656
657                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
658                         OnUpdating (args);
659                         if (args.Cancel)
660                                 return -1;
661                         
662                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
663                         OnUpdated (rargs);
664                         
665                         if (rargs.Exception != null && !rargs.ExceptionHandled)
666                                 throw rargs.Exception;
667
668                         if (owner.EnableCaching)
669                                 owner.Cache.Expire ();
670                         
671                         OnDataSourceViewChanged (EventArgs.Empty);
672
673                         return -1;
674                 }
675
676                 private IDictionary BuildOldValuesList (IDictionary keys, IDictionary oldValues, bool keysWin) 
677                 {
678                         IDictionary oldDataValues;
679                         if (ConflictDetection == ConflictOptions.CompareAllValues) {
680                                 oldDataValues = new Hashtable ();
681                                 if (keys != null && !keysWin) {
682                                         foreach (DictionaryEntry de in keys)
683                                                 oldDataValues [de.Key] = de.Value;
684                                 }
685                                 if (oldValues != null) {
686                                         foreach (DictionaryEntry de in oldValues)
687                                                 oldDataValues [de.Key] = de.Value;
688                                 }
689                                 if (keys != null && keysWin) {
690                                         foreach (DictionaryEntry de in keys)
691                                                 oldDataValues [de.Key] = de.Value;
692                                 }
693                         }
694                         else {
695                                 oldDataValues = keys;
696                         }
697
698                         return oldDataValues;
699                 }
700
701                 protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments)
702                 {
703                         arguments.RaiseUnsupportedCapabilitiesError (this);
704
705                         IOrderedDictionary paramValues = MergeParameterValues (SelectParameters, null, null);
706                         ObjectDataSourceSelectingEventArgs args = new ObjectDataSourceSelectingEventArgs (paramValues, arguments, false);
707
708                         object result = null;
709
710                         if (owner.EnableCaching)
711                                 result = owner.Cache.GetCachedObject (SelectMethod, SelectParameters);
712
713                         if (result == null) {
714                                 OnSelecting (args);
715                                 if (args.Cancel)
716                                         return new ArrayList ();
717
718                                 if (CanRetrieveTotalRowCount && arguments.RetrieveTotalRowCount)
719                                         arguments.TotalRowCount = QueryTotalRowCount (paramValues, arguments);
720
721                                 if (CanPage) {
722                                         if (StartRowIndexParameterName.Length == 0)
723                                                 throw new InvalidOperationException ("Paging is enabled, but the StartRowIndexParameterName property is not set.");
724                                         if (MaximumRowsParameterName.Length == 0)
725                                                 throw new InvalidOperationException ("Paging is enabled, but the MaximumRowsParameterName property is not set.");
726                                         paramValues [StartRowIndexParameterName] = arguments.StartRowIndex;
727                                         paramValues [MaximumRowsParameterName] = arguments.MaximumRows;
728                                 }
729
730                                 if (SortParameterName.Length > 0)
731                                         paramValues [SortParameterName] = arguments.SortExpression;
732
733                                 result = InvokeSelect (SelectMethod, paramValues);
734
735                                 if (owner.EnableCaching)
736                                         owner.Cache.SetCachedObject (SelectMethod, SelectParameters, result);
737                         }
738
739                         if (FilterExpression.Length > 0 && !(result is DataGrid || result is DataView || result is DataTable))
740                                 throw new NotSupportedException ("The FilterExpression property was set and the Select method does not return a DataSet, DataTable, or DataView.");
741
742                         if (owner.EnableCaching && result is IDataReader)
743                                 throw new NotSupportedException ("Data source does not support caching objects that implement IDataReader");
744                         
745                         if (result is DataSet) {
746                                 DataSet dset = (DataSet) result;
747                                 if (dset.Tables.Count == 0)
748                                         throw new InvalidOperationException ("The select method returnet a DataSet which doesn't contain any table.");
749                                 result = dset.Tables [0];
750                         }
751                         
752                         if (result is DataTable) {
753                                 DataView dview = new DataView ((DataTable)result);
754                                 if (arguments.SortExpression != null && arguments.SortExpression.Length > 0) {
755                                         dview.Sort = arguments.SortExpression;
756                                 }
757                                 if (FilterExpression.Length > 0) {
758                                         IOrderedDictionary fparams = FilterParameters.GetValues (context, owner);
759                                         ObjectDataSourceFilteringEventArgs fargs = new ObjectDataSourceFilteringEventArgs (fparams);
760                                         OnFiltering (fargs);
761                                         if (!fargs.Cancel) {
762                                                 object[] formatValues = new object [fparams.Count];
763                                                 for (int n=0; n<formatValues.Length; n++) {
764                                                         formatValues [n] = fparams [n];
765                                                         if (formatValues [n] == null) return dview;
766                                                 }
767                                                 dview.RowFilter = string.Format (FilterExpression, formatValues);
768                                         }
769                                 }
770                                 return dview;
771                         }
772                         
773                         if (result is IEnumerable)
774                                 return (IEnumerable) result;
775                         else
776                                 return new object[] { result };
777                 }
778                 
779                 int QueryTotalRowCount (IOrderedDictionary mergedParameters, DataSourceSelectArguments arguments)
780                 {
781                         ObjectDataSourceSelectingEventArgs countArgs = new ObjectDataSourceSelectingEventArgs (mergedParameters, arguments, true);
782                         OnSelecting (countArgs);
783                         if (countArgs.Cancel)
784                                 return 0;
785                         
786                         object count = InvokeSelect (SelectCountMethod, mergedParameters);
787                         return (int) Convert.ChangeType (count, typeof(int));
788                 }
789                 
790                 object InvokeSelect (string methodName, IOrderedDictionary paramValues)
791                 {
792                         MethodInfo method = GetObjectMethod (methodName, paramValues, DataObjectMethodType.Select);
793                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
794                         OnSelected (rargs);
795                         
796                         if (rargs.Exception != null && !rargs.ExceptionHandled)
797                                 throw rargs.Exception;
798
799                         return rargs.ReturnValue;
800                 }
801                 
802                 ObjectDataSourceStatusEventArgs InvokeMethod (MethodInfo method, IOrderedDictionary paramValues)
803                 {
804                         object instance = null;
805
806                         if (!method.IsStatic)
807                                 instance = CreateObjectInstance ();
808
809                         ParameterInfo[] pars = method.GetParameters ();
810                         
811                         ArrayList outParamInfos;
812                         object[] methodArgs = GetParameterArray (pars, paramValues, out outParamInfos); 
813                         
814                         if (methodArgs == null)
815                                 throw CreateMethodException (method.Name, paramValues);
816                                         
817                         object result = null;
818                         Hashtable outParams = null;
819                         
820                         try {
821                                 result = method.Invoke (instance, methodArgs);
822                                 if (outParamInfos != null) {
823                                         outParams = new Hashtable ();
824                                         foreach (ParameterInfo op in outParamInfos)
825                                                 outParams [op.Name] = methodArgs [op.Position];
826                                 }
827                                 return new ObjectDataSourceStatusEventArgs (result, outParams, null);
828                         }
829                         catch (Exception ex) {
830                                 return new ObjectDataSourceStatusEventArgs (result, outParams, ex);
831                         }
832                         finally {
833                                 if (instance != null)
834                                         DisposeObjectInstance (instance);
835                         }
836                 }
837                 
838                 MethodInfo GetObjectMethod (string methodName, IOrderedDictionary parameters, DataObjectMethodType methodType)
839                 {
840                         MemberInfo[] methods = ObjectType.GetMember (methodName, MemberTypes.Method, BindingFlags.Instance | 
841                                                                                  BindingFlags.Static | 
842                                                                                  BindingFlags.Public | 
843                                                                                  BindingFlags.IgnoreCase |
844                                                                                  BindingFlags.FlattenHierarchy);
845                         if (methods.Length > 1) {
846                                 // MSDN: The ObjectDataSource resolves method overloads by method name and number
847                                 // of parameters; the names and types of the parameters are not considered.
848                                 // LAMESPEC: the tests show otherwise
849                                 DataObjectMethodAttribute methodAttribute = null;
850                                 MethodInfo methodInfo = null;
851                                 bool hasConflict = false;
852                                 foreach (MethodInfo me in methods) { // we look for methods only
853                                         ParameterInfo [] pinfos = me.GetParameters ();
854                                         if (pinfos.Length == parameters.Count) {
855                                                 object [] attrs = me.GetCustomAttributes (typeof (DataObjectMethodAttribute), true);
856                                                 DataObjectMethodAttribute domAttr = (attrs != null && attrs.Length > 0) ? (DataObjectMethodAttribute) attrs [0] : null;
857                                                 if (domAttr != null && domAttr.MethodType != methodType)
858                                                         continue;
859
860                                                 bool paramsMatch = true;
861                                                 foreach (ParameterInfo pinfo in pinfos) {
862                                                         if (!parameters.Contains (pinfo.Name)) {
863                                                                 paramsMatch = false;
864                                                                 break;
865                                                         }
866                                                 }
867
868                                                 if (!paramsMatch)
869                                                         continue;
870
871                                                 if (domAttr != null) {
872                                                         if (methodAttribute != null) {
873                                                                 if (methodAttribute.IsDefault) {
874                                                                         if (domAttr.IsDefault) {
875                                                                                 methodInfo = null;
876                                                                                 break; //fail due to a conflict
877                                                                         }
878                                                                         else
879                                                                                 continue; //existing matches better
880                                                                 }
881                                                                 else {
882                                                                         methodInfo = null; //we override
883                                                                         hasConflict = !domAttr.IsDefault;
884                                                                 }
885                                                         }
886                                                         else
887                                                                 methodInfo = null; //we override
888                                                 }
889
890                                                 if (methodInfo == null) {
891                                                         methodAttribute = domAttr;
892                                                         methodInfo = me;
893                                                         continue;
894                                                 }
895
896                                                 hasConflict = true;
897                                         }
898                                 }
899
900                                 if (!hasConflict && methodInfo != null)
901                                         return methodInfo;
902                         }
903                         else if (methods.Length == 1) {
904                                 MethodInfo me = methods[0] as MethodInfo;
905                                 if (me != null && me.GetParameters().Length == parameters.Count)
906                                         return me;
907                         }
908                         
909                         throw CreateMethodException (methodName, parameters);
910                 }
911                 
912                 MethodInfo ResolveDataObjectMethod (string methodName, IDictionary values, IDictionary oldValues, out IOrderedDictionary paramValues)
913                 {
914                         MethodInfo method;
915                         if (oldValues != null)
916                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType, DataObjectType });
917                         else
918                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType });
919                         
920                         if (method == null)
921                                 throw new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters of type '" + DataObjectType + "' in '" + ObjectType + "'.");
922
923                         paramValues = new OrderedDictionary (StringComparer.InvariantCultureIgnoreCase);
924                         ParameterInfo[] ps = method.GetParameters ();
925                         
926                         if (oldValues != null) {
927                                 if (FormatOldParameter (ps[0].Name) == ps[1].Name) {
928                                         paramValues [ps[0].Name] = CreateDataObject (values);
929                                         paramValues [ps[1].Name] = CreateDataObject (oldValues);
930                                 } else if (FormatOldParameter (ps[1].Name) == ps[0].Name) {
931                                         paramValues [ps[0].Name] = CreateDataObject (oldValues);
932                                         paramValues [ps[1].Name] = CreateDataObject (values);
933                                 } else
934                                         throw new InvalidOperationException ("Method '" + methodName + "' does not have any parameter that fits the value of OldValuesParameterFormatString.");  
935                         } else {
936                                 paramValues [ps[0].Name] = CreateDataObject (values);
937                         }
938                         return method;
939                 }
940                 
941                 Exception CreateMethodException (string methodName, IOrderedDictionary parameters)
942                 {
943                         string s = "";
944                         foreach (string p in parameters.Keys) {
945                                 s += p + ", ";
946                         }
947                         return new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters " + s + "in type '" + ObjectType + "'.");
948                 }
949                 
950                 object CreateDataObject (IDictionary values)
951                 {
952                         object ob = Activator.CreateInstance (DataObjectType);
953                         foreach (DictionaryEntry de in values) {
954                                 PropertyInfo p = DataObjectType.GetProperty ((string)de.Key);
955                                 if (p == null) throw new InvalidOperationException ("Property " + de.Key + " not found in type '" +DataObjectType + "'.");
956                                 object[] attributes = p.GetCustomAttributes (typeof (System.ComponentModel.TypeConverterAttribute),
957                                                                              true);
958                                 Type propertyType = p.PropertyType;
959                                 object value = de.Value;
960                                 object converted = ConvertParameterWithTypeConverter (attributes, propertyType, value);
961                                 if (converted == null)
962                                         converted = ConvertParameter (propertyType, value);
963                                                    
964                                 p.SetValue (ob, converted, null);
965                         }
966                         return ob;
967                 }
968                 
969                 object CreateObjectInstance ()
970                 {
971                         ObjectDataSourceEventArgs args = new ObjectDataSourceEventArgs (null);
972                         OnObjectCreating (args);
973                         
974                         if (args.ObjectInstance != null)
975                                 return args.ObjectInstance;
976                                 
977                         object ob = Activator.CreateInstance (ObjectType);
978                         
979                         args.ObjectInstance = ob;
980                         OnObjectCreated (args);
981                         
982                         return args.ObjectInstance;
983                 }
984                 
985                 void DisposeObjectInstance (object obj)
986                 {
987                         ObjectDataSourceDisposingEventArgs args = new ObjectDataSourceDisposingEventArgs (obj);
988                         OnObjectDisposing (args);
989                         
990                         if (!args.Cancel) {
991                                 IDisposable disp = obj as IDisposable;
992                                 if (disp != null) disp.Dispose ();
993                         }
994                 }
995
996                 object FindValueByName (string name, IDictionary values, bool format)
997                 {
998                         if (values == null)
999                                 return null;
1000
1001                         foreach (DictionaryEntry de in values) {
1002                                 string valueName = format == true ? FormatOldParameter (de.Key.ToString ()) : de.Key.ToString ();
1003                                 if (String.Compare (name, valueName, StringComparison.InvariantCultureIgnoreCase) == 0)
1004                                         return values [de.Key];
1005                         }
1006                         return null;
1007                 }
1008
1009                 /// <summary>
1010                 /// Merge the current data item fields with view parameter default values
1011                 /// </summary>
1012                 /// <param name="viewParams">default parameters</param>
1013                 /// <param name="values">new parameters for update and insert</param>
1014                 /// <param name="oldValues">old parameters for update and delete</param>
1015                 /// <param name="allwaysAddNewValues">true for insert, as current item is
1016                 /// irrelevant for insert</param>
1017                 /// <returns>merged values</returns>
1018                 IOrderedDictionary MergeParameterValues (ParameterCollection viewParams, IDictionary values, IDictionary oldValues)
1019                 {
1020                         IOrderedDictionary parametersValues = viewParams.GetValues (context, owner);
1021                         OrderedDictionary mergedValues = new OrderedDictionary (StringComparer.InvariantCultureIgnoreCase);
1022                         foreach (string parameterName in parametersValues.Keys) {
1023                                 mergedValues [parameterName] = parametersValues [parameterName];
1024                                 if (oldValues != null) {
1025                                         object value = FindValueByName (parameterName, oldValues, true);
1026                                         if (value != null) {
1027                                                 object dataValue = viewParams [parameterName].ConvertValue (value);
1028                                                 mergedValues [parameterName] = dataValue;
1029                                         }
1030                                 }
1031
1032                                 if (values != null) {
1033                                         object value = FindValueByName (parameterName, values, false);
1034                                         if (value != null) {
1035                                                 object dataValue = viewParams [parameterName].ConvertValue (value);
1036                                                 mergedValues [parameterName] = dataValue;
1037                                         }
1038                                 }
1039                         }
1040
1041                         if (values != null) {
1042                                 foreach (DictionaryEntry de in values)
1043                                         if (FindValueByName ((string) de.Key, mergedValues, false) == null)
1044                                                 mergedValues [de.Key] = de.Value;
1045                         }
1046
1047                         if (oldValues != null) {
1048                                 foreach (DictionaryEntry de in oldValues) {
1049                                         string oldValueKey = FormatOldParameter ((string) de.Key);
1050                                         if (FindValueByName (oldValueKey, mergedValues, false) == null)
1051                                                 mergedValues [oldValueKey] = de.Value;
1052                                 }
1053                         }
1054
1055                         return mergedValues;
1056                 }
1057                 
1058                 object[] GetParameterArray (ParameterInfo[] methodParams, IOrderedDictionary viewParams, out ArrayList outParamInfos)
1059                 {
1060                         // FIXME: make this case insensitive
1061
1062                         outParamInfos = null;
1063                         object[] values = new object [methodParams.Length];
1064                         
1065                         foreach (ParameterInfo mp in methodParams) {
1066                         
1067                                 // Parameter names must match
1068                                 if (!viewParams.Contains (mp.Name)) return null;
1069                                 
1070                                 values [mp.Position] = ConvertParameter (mp.ParameterType, viewParams [mp.Name]);
1071                                 if (mp.ParameterType.IsByRef) {
1072                                         if (outParamInfos == null) outParamInfos = new ArrayList ();
1073                                         outParamInfos.Add (mp);
1074                                 }
1075                         }
1076                         return values;
1077                 }
1078
1079                 object ConvertParameterWithTypeConverter (object[] attributes, Type targetType, object value)
1080                 {
1081                         if (attributes == null || attributes.Length == 0 || value == null)
1082                                 return null;
1083                         TypeConverterAttribute tca;
1084                         Type converterType;
1085                         TypeConverter converter;
1086                         
1087                         foreach (object a in attributes) {
1088                                 tca = a as TypeConverterAttribute;
1089                                 if (tca == null)
1090                                         continue;
1091                                 converterType = HttpApplication.LoadType (tca.ConverterTypeName, false);
1092                                 if (converterType == null)
1093                                         continue;
1094                                 converter = Activator.CreateInstance (converterType, new object[] {targetType}) as TypeConverter;
1095                                 if (converter == null)
1096                                         continue;
1097                                 if (converter.CanConvertFrom (value.GetType ()))
1098                                         return converter.ConvertFrom (value);
1099                                 else if (converter.CanConvertFrom (typeof (string)))
1100                                         return converter.ConvertFrom (value.ToString ());
1101                         }
1102                         
1103                         return null;
1104                 }
1105                 
1106                 object ConvertParameter (Type targetType, object value)
1107                 {
1108                         return ConvertParameter (Type.GetTypeCode (targetType), value);
1109                 }
1110                 
1111                 object ConvertParameter (TypeCode targetType, object value)
1112                 {
1113                         if (value == null) {
1114                                 if (targetType != TypeCode.Object && targetType != TypeCode.String)
1115                                         value = 0;
1116                                 else if (ConvertNullToDBNull)
1117                                         return DBNull.Value;
1118                         }
1119                         if (targetType == TypeCode.Object || targetType == TypeCode.Empty)
1120                                 return value;
1121                         else
1122                                 return Convert.ChangeType (value, targetType);
1123                 }
1124                 
1125                 string FormatOldParameter (string name)
1126                 {
1127                         string f = OldValuesParameterFormatString;
1128                         if (f.Length > 0)
1129                                 return String.Format (f, name);
1130                         else
1131                                 return name;
1132                 }
1133                 
1134                 void OnParametersChanged (object sender, EventArgs args)
1135                 {
1136                         OnDataSourceViewChanged (EventArgs.Empty);
1137                 }
1138                 
1139                 protected virtual void LoadViewState (object savedState)
1140                 {
1141                         object[] state = (savedState == null) ? new object [5] : (object[]) savedState;
1142                         ((IStateManager)SelectParameters).LoadViewState (state[0]); 
1143                         ((IStateManager)UpdateParameters).LoadViewState (state[1]); 
1144                         ((IStateManager)DeleteParameters).LoadViewState (state[2]); 
1145                         ((IStateManager)InsertParameters).LoadViewState (state[3]); 
1146                         ((IStateManager)FilterParameters).LoadViewState (state[4]); 
1147                 }
1148
1149                 protected virtual object SaveViewState()
1150                 {
1151                         object[] state = new object [5];
1152                         
1153                         if (selectParameters != null)
1154                                 state [0] = ((IStateManager)selectParameters).SaveViewState ();
1155                         if (updateParameters != null)
1156                                 state [1] = ((IStateManager)updateParameters).SaveViewState ();
1157                         if (deleteParameters != null)
1158                                 state [2] = ((IStateManager)deleteParameters).SaveViewState ();
1159                         if (insertParameters != null)
1160                                 state [3] = ((IStateManager)insertParameters).SaveViewState ();
1161                         if (filterParameters != null)
1162                                 state [4] = ((IStateManager)filterParameters).SaveViewState ();
1163                         
1164                         foreach (object ob in state)
1165                                 if (ob != null) return state;
1166                         
1167                         return null;
1168                 }
1169                 
1170                 protected virtual void TrackViewState()
1171                 {
1172                         isTrackingViewState = true;
1173
1174                         if (selectParameters != null) ((IStateManager)selectParameters).TrackViewState ();
1175                         if (filterParameters != null) ((IStateManager)filterParameters).TrackViewState ();
1176                 }
1177                 
1178                 protected bool IsTrackingViewState
1179                 {
1180                         get { return isTrackingViewState; }
1181                 }
1182                 
1183                 
1184                 bool IStateManager.IsTrackingViewState
1185                 {
1186                         get { return IsTrackingViewState; }
1187                 }
1188                 
1189                 void IStateManager.TrackViewState()
1190                 {
1191                         TrackViewState ();
1192                 }
1193                 
1194                 void IStateManager.LoadViewState (object savedState)
1195                 {
1196                         LoadViewState (savedState);
1197                 }
1198
1199                 object IStateManager.SaveViewState()
1200                 {
1201                         return SaveViewState ();
1202                 }
1203         }
1204 }
1205 #endif
1206
1207
1208
1209
1210