Explorar el Código

Added column and reference caching to ColumnReference.

svn path=/trunk/mcs/; revision=55710
Boris Kirzner hace 20 años
padre
commit
db5969ed84

+ 4 - 0
mcs/class/System.Data/Mono.Data.SqlExpressions/ChangeLog

@@ -1,3 +1,7 @@
+2006-01-18 Boris Kirzner <[email protected]>
+	* ColumnReference.cs: added column and relation lazy evaluation 
+	and caching.
+
 2006-01-09 Senganal T <[email protected]>
 	* Aggregation.cs
 	* Expression.cs

+ 113 - 19
mcs/class/System.Data/Mono.Data.SqlExpressions/ColumnReference.cs

@@ -33,6 +33,7 @@
 using System;
 using System.Collections;
 using System.Data;
+using System.ComponentModel;
 
 namespace Mono.Data.SqlExpressions {
 	internal enum ReferencedTable {
@@ -44,6 +45,8 @@ namespace Mono.Data.SqlExpressions {
 	internal class ColumnReference : BaseExpression {
 		ReferencedTable refTable;
 		string relationName, columnName;
+		DataColumn _cachedColumn;
+		DataRelation _cachedRelation;
 
 		public ColumnReference (string columnName) : this (ReferencedTable.Self, null, columnName) {}
 
@@ -88,26 +91,55 @@ namespace Mono.Data.SqlExpressions {
 			get { return refTable; }
 		}
 
-		protected DataRelation GetRelation (DataRow row)
+		private DataRelation GetRelation (DataRow row)
 		{
-			DataRelationCollection relations;
-			if (relationName != null) {
-				relations = row.Table.DataSet.Relations;
-				return relations[relations.IndexOf(relationName)];
+			if (_cachedRelation == null) {
+				DataTable table = row.Table;
+				DataRelationCollection relations;
+				if (relationName != null) {
+					relations = table.DataSet.Relations;
+					_cachedRelation = relations [relations.IndexOf (relationName)];
+				}
+				else {
+					if (refTable == ReferencedTable.Parent)
+						relations = table.ParentRelations;
+					else
+						relations = table.ChildRelations;
+						
+					if (relations.Count > 1)
+						throw new EvaluateException (String.Format (
+							"The table [{0}] is involved in more than one relation." +
+							"You must explicitly mention a relation name.",
+							table.TableName));
+					else
+						_cachedRelation = relations [0];
+				}
+				_cachedRelation.DataSet.Relations.CollectionChanged += new CollectionChangeEventHandler (OnRelationRemoved);
 			}
+			return _cachedRelation;
+		}
 
-			if (refTable == ReferencedTable.Parent)
-				relations = row.Table.ParentRelations;
-			else
-				relations = row.Table.ChildRelations;
-				
-			if (relations.Count > 1)
-				throw new EvaluateException (String.Format (
-					"The table [{0}] is involved in more than one relation." +
-					"You must explicitly mention a relation name.",
-					row.Table.TableName));
-			else
-				return relations[0];
+		private DataColumn GetColumn (DataRow row)
+		{
+			if (_cachedColumn == null) {
+				DataTable table = row.Table;
+				switch (refTable) {
+					case ReferencedTable.Parent:
+						table = GetRelation (row).ParentTable;
+						break;
+					case ReferencedTable.Child:
+						table = GetRelation (row).ChildTable;
+						break;
+				}
+
+				_cachedColumn = table.Columns [columnName];
+				if (_cachedColumn == null)
+					throw new EvaluateException (String.Format ("Cannot find column [{0}].", columnName));
+
+				_cachedColumn.PropertyChanged += new PropertyChangedEventHandler (OnColumnPropertyChanged);
+				_cachedColumn.Table.Columns.CollectionChanged += new CollectionChangeEventHandler (OnColumnRemoved);
+			}
+			return _cachedColumn;
 		}
 
 		public DataRow GetReferencedRow (DataRow row)
@@ -146,7 +178,7 @@ namespace Mono.Data.SqlExpressions {
 		{
 			object[] values = new object [rows.Length];
 			for (int i = 0; i < rows.Length; i++)
-				values [i] = Unify (rows [i][columnName]);
+				values [i] = Unify (rows [i][GetColumn (rows [i])]);
 				
 			return values;
 		}
@@ -176,7 +208,7 @@ namespace Mono.Data.SqlExpressions {
 			object val;
 			try {
 				referencedRow._inExpressionEvaluation = true;
-				val = referencedRow [columnName];
+				val = referencedRow [GetColumn (row)];
 				referencedRow._inExpressionEvaluation = false;
 			} catch (IndexOutOfRangeException) {
 				throw new EvaluateException (String.Format ("Cannot find column [{0}].", columnName));
@@ -188,5 +220,67 @@ namespace Mono.Data.SqlExpressions {
 		{
 			return refTable == ReferencedTable.Self && columnName == other.ColumnName;
 		}
+
+		private void DropCached (DataColumnCollection columnCollection, DataRelationCollection relationCollection)
+		{
+			if (_cachedColumn != null) {
+				// unregister column listener
+				_cachedColumn.PropertyChanged -= new PropertyChangedEventHandler (OnColumnPropertyChanged);
+
+				// unregister column collection listener
+				if (columnCollection != null)	
+					columnCollection.CollectionChanged -= new CollectionChangeEventHandler (OnColumnRemoved);
+				else if (_cachedColumn.Table != null)
+					_cachedColumn.Table.Columns.CollectionChanged -= new CollectionChangeEventHandler (OnColumnRemoved);
+				
+				_cachedColumn = null;
+			}
+
+			if (_cachedRelation != null) {
+				// unregister relation collection listener
+				if (relationCollection != null)				
+					relationCollection.CollectionChanged -= new CollectionChangeEventHandler (OnRelationRemoved);
+				else if (_cachedRelation.DataSet != null)
+					_cachedRelation.DataSet.Relations.CollectionChanged -= new CollectionChangeEventHandler (OnRelationRemoved);
+
+				_cachedRelation = null;
+			}			
+		}
+
+		private void OnColumnPropertyChanged (object sender, PropertyChangedEventArgs args)
+		{
+			if (!(sender is DataColumn))
+				return;
+			
+			DataColumn dc = (DataColumn) sender;
+			if ((dc == _cachedColumn) && args.PropertyName == "ColumnName")
+				DropCached (null, null);
+		}
+
+		private void OnColumnRemoved (object sender, CollectionChangeEventArgs args)
+		{
+			if (!(args.Element is DataColumnCollection))
+				return;
+
+			if (args.Action != CollectionChangeAction.Remove)
+				return;
+
+			DataColumnCollection columnCollection = (DataColumnCollection) args.Element;
+			if (_cachedColumn != null && columnCollection != null && (columnCollection.IndexOf (_cachedColumn)) == -1)
+				DropCached (columnCollection, null);
+		}
+
+		private void OnRelationRemoved (object sender, CollectionChangeEventArgs args)
+		{
+			if (!(args.Element is DataRelationCollection))
+				return;
+
+			if (args.Action != CollectionChangeAction.Remove)
+				return;			
+
+			DataRelationCollection relationCollection = (DataRelationCollection) args.Element;
+			if (_cachedRelation != null && relationCollection != null && (relationCollection.IndexOf (_cachedRelation)) == -1)
+				DropCached (null, relationCollection);
+		}
 	}
 }

+ 3 - 0
mcs/class/System.Data/System.Data/ChangeLog

@@ -1,3 +1,6 @@
+2006-01-18 Boris Kirzner <[email protected]>
+	* DataColumn.cs: added PropertyCchangedEvent handling.
+
 2006-01-17  Senganal T  <[email protected]>
 	
 	* DataRow.cs:

+ 6 - 2
mcs/class/System.Data/System.Data/DataColumn.cs

@@ -68,6 +68,8 @@ namespace System.Data {
 
 		//used for FK Constraint Cascading rules
 		internal event DelegateColumnValueChange ColumnValueChanging;
+
+		internal event PropertyChangedEventHandler PropertyChanged;
 		#endregion //Events
 		
 		#region Fields
@@ -772,13 +774,15 @@ namespace System.Data {
 			throw new NotImplementedException ();
 		}
 
-		[MonoTODO]
 		protected internal virtual void 
 		OnPropertyChanging (PropertyChangedEventArgs pcevent) {
+			if (PropertyChanged != null)
+				PropertyChanged (this, pcevent);
 		}
 
-		[MonoTODO]
 		protected internal void RaisePropertyChanging(string name) {
+			PropertyChangedEventArgs e = new PropertyChangedEventArgs (name);
+			OnPropertyChanging (e);
 		}
 
 		/// <summary>