// // LinqDataSourceView.cs // // Author: // Atsushi Enomoto // // Copyright (C) 2008 Novell, Inc http://novell.com // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // FIXME: in general we should create something like // System.Web.Query,Dynamic.DynamicClass to execute DataContext operations. using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data.Linq; using System.Reflection; using System.Security.Permissions; using System.Web.DynamicData; using System.Web.UI; namespace System.Web.UI.WebControls { [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] public class LinqDataSourceView : DataSourceView, IStateManager { public LinqDataSourceView (LinqDataSource owner, string name, HttpContext context) : base (owner, name) { source = owner; } LinqDataSource source; bool tracking; ParameterCollection delete_parameters, insert_parameters, select_new_parameters, update_parameters; ParameterCollection group_by_parameters, order_by_parameters, order_group_by_parameters, where_parameters; IEnumerable AllParameters { get { yield return delete_parameters; yield return insert_parameters; yield return select_new_parameters; yield return update_parameters; yield return group_by_parameters; yield return order_by_parameters; yield return order_group_by_parameters; yield return where_parameters; } } [MonoTODO] public bool AutoGenerateOrderByClause { get; set; } [MonoTODO] public bool AutoGenerateWhereClause { get; set; } [MonoTODO] public bool AutoPage { get; set; } [MonoTODO] public bool AutoSort { get; set; } public override bool CanDelete { get { return EnableDelete; } } public override bool CanInsert { get { return EnableInsert; } } public override bool CanPage { get { return true; } } public override bool CanRetrieveTotalRowCount { get { return true; } } public override bool CanSort { get { return true; } } public override bool CanUpdate { get { return EnableUpdate; } } protected virtual Type ContextType { get { return ((IDynamicDataSource) source).ContextType; } } public virtual string ContextTypeName { get { return source.ContextTypeName; } set { source.ContextTypeName = value; } } [MonoTODO] public bool EnableDelete { get; set; } [MonoTODO] public bool EnableInsert { get; set; } [MonoTODO] public bool EnableObjectTracking { get; set; } [MonoTODO] public bool EnableUpdate { get; set; } [MonoTODO] public string TableName { get; set; } [MonoTODO] public string GroupBy { get; set; } [MonoTODO] public string OrderBy { get; set; } [MonoTODO] public string OrderGroupsBy { get; set; } [MonoTODO] public string SelectNew { get; set; } [MonoTODO] public string Where { get; set; } public ParameterCollection DeleteParameters { get { return GetParameterCollection (ref delete_parameters, false, false); } } public ParameterCollection InsertParameters { get { return GetParameterCollection (ref insert_parameters, false, false); } } public ParameterCollection UpdateParameters { get { return GetParameterCollection (ref update_parameters, true, true); } } public ParameterCollection SelectNewParameters { get { return GetParameterCollection (ref select_new_parameters, false, false); } } public ParameterCollection WhereParameters { get { return GetParameterCollection (ref where_parameters, true, true); } } public ParameterCollection GroupByParameters { get { return GetParameterCollection (ref group_by_parameters, true, true); } } public ParameterCollection OrderByParameters { get { return GetParameterCollection (ref order_by_parameters, true, true); } } public ParameterCollection OrderGroupsByParameters { get { return GetParameterCollection (ref order_group_by_parameters, true, true); } } ParameterCollection GetParameterCollection (ref ParameterCollection output, bool propagateTrackViewState, bool subscribeChanged) { if (output != null) return output; output = new ParameterCollection (); if (subscribeChanged) output.ParametersChanged += new EventHandler (ParametersChanged); if (IsTrackingViewState && propagateTrackViewState) ((IStateManager) output).TrackViewState (); return output; } void ParametersChanged (object source, EventArgs args) { OnDataSourceViewChanged (EventArgs.Empty); } object data_context; object GetDataContext () { if (data_context == null) data_context = CreateContext (ContextType); return data_context; } public int Delete (IDictionary keys, IDictionary oldValues) { return ExecuteDelete (keys, oldValues); } public int Insert (IDictionary values) { return ExecuteInsert (values); } public IEnumerable Select (DataSourceSelectArguments arguments) { return ExecuteSelect (arguments); } public int Update (IDictionary keys, IDictionary values, IDictionary oldValues) { return ExecuteUpdate (keys, values, oldValues); } [MonoTODO] protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues) { throw new NotImplementedException (); } protected override int ExecuteInsert (IDictionary values) { var dc = (DataContext) GetDataContext (); foreach (var mt in dc.Mapping.GetTables ()) { if (mt.TableName != TableName) continue; var t = mt.RowType.Type; ITable table = dc.GetTable (t); object entity = Activator.CreateInstance (t); // FIXME: merge InsertParameters foreach (DictionaryEntry p in values) t.GetProperty ((string) p.Key).SetValue (entity, p.Value, null); InsertDataObject (dc, table, entity); return 1; } throw new InvalidOperationException (String.Format ("Table '{0}' was not found on the data context '{1}'", TableName, ContextType)); } [MonoTODO] protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues) { throw new NotImplementedException (); } [MonoTODO] protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments) { int max = arguments.MaximumRows; max = max == 0 ? int.MaxValue : max; int total = arguments.TotalRowCount; total = total < 0 ? int.MaxValue : total; int end = total == int.MaxValue ? total : arguments.StartRowIndex + total; DataContext dc = Activator.CreateInstance (ContextType, true) as DataContext; MemberInfo mi = GetTableMemberInfo (dc.GetType ()); // am totally not sure it is fine. IEnumerable results; if (source.Select != null) { // FIXME: merge SelectParameters. results = dc.ExecuteQuery (mi is FieldInfo ? ((FieldInfo) mi).FieldType : ((PropertyInfo) mi).PropertyType, source.Select, new object [0]); } else { results = (IEnumerable) (mi is FieldInfo ? ((FieldInfo) mi).GetValue (dc) : ((PropertyInfo) mi).GetValue (dc, null)); } int i = 0; foreach (var e in results) { if (i++ < arguments.StartRowIndex) continue; // skip rows before StartRowIndex. if (i < end) yield return e; } } protected virtual void DeleteDataObject (object dataContext, object table, object oldDataObject) { ITable itable = ((DataContext) dataContext).GetTable (table.GetType ()); itable.DeleteOnSubmit (oldDataObject); } protected virtual void InsertDataObject (object dataContext, object table, object newDataObject) { ITable itable = ((DataContext) dataContext).GetTable (table.GetType ()); itable.InsertOnSubmit (newDataObject); } [MonoTODO] protected virtual void ResetDataObject (object table, object dataObject) { var dc = GetDataContext (); ITable itable = ((DataContext) dc).GetTable (table.GetType ()); UpdateDataObject (dc, table, dataObject, itable.GetOriginalEntityState (dataObject)); } protected virtual void UpdateDataObject (object dataContext, object table, object oldDataObject, object newDataObject) { DeleteDataObject (dataContext, table, oldDataObject); InsertDataObject (dataContext, table, newDataObject); } protected virtual object CreateContext (Type contextType) { OnContextCreating (new LinqDataSourceContextEventArgs ()); var o = Activator.CreateInstance (contextType); OnContextCreated (new LinqDataSourceStatusEventArgs (o)); return o; } [MonoTODO] protected virtual Type GetDataObjectType (Type tableType) { throw new NotImplementedException (); } MemberInfo table_member; protected virtual MemberInfo GetTableMemberInfo (Type contextType) { if (contextType == null) throw new ArgumentNullException ("contextType"); if (String.IsNullOrEmpty (TableName)) throw new InvalidOperationException (String.Format ("The TableName property of LinqDataSource '{0}' must specify a table property or field on the data context type.", source.ID)); if (table_member != null && table_member.DeclaringType == contextType) return table_member; var marr = contextType.GetMember (TableName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty); if (marr == null || marr.Length == 0) throw new InvalidOperationException (String.Format ("Could not find a property or field called '{0}' on the data context type '{1}' of LinqDataSource '{2}'", TableName, contextType, source.ID)); table_member = marr [0]; return table_member; } #region Validation [MonoTODO] protected virtual void ValidateContextType (Type contextType, bool selecting) { throw new NotImplementedException (); } [MonoTODO] protected virtual void ValidateDeleteSupported (IDictionary keys, IDictionary oldValues) { throw new NotImplementedException (); } [MonoTODO] protected virtual void ValidateInsertSupported (IDictionary values) { throw new NotImplementedException (); } [MonoTODO] protected virtual void ValidateOrderByParameter (string name, string value) { throw new NotImplementedException (); } [MonoTODO] protected virtual void ValidateParameterName (string name) { throw new NotImplementedException (); } [MonoTODO] protected virtual void ValidateTableType (Type tableType, bool selecting) { throw new NotImplementedException (); } [MonoTODO] protected virtual void ValidateUpdateSupported (IDictionary keys, IDictionary values, IDictionary oldValues) { throw new NotImplementedException (); } #endregion #region ViewState bool IStateManager.IsTrackingViewState { get { return IsTrackingViewState; } } protected bool IsTrackingViewState { get { return tracking; } } [MonoTODO] public bool StoreOriginalValuesInViewState { get { throw new NotImplementedException (); } set { throw new NotImplementedException (); } } void IStateManager.LoadViewState (object savedState) { LoadViewState (savedState); } object IStateManager.SaveViewState () { return SaveViewState (); } void IStateManager.TrackViewState () { TrackViewState (); } protected virtual void LoadViewState (object savedState) { object [] vs = savedState as object []; if (vs == null) return; int i = 0; foreach (var p in AllParameters) { if (vs [i] != null) ((IStateManager) p).LoadViewState (vs [i]); i++; } } protected virtual object SaveViewState () { object [] vs = new object [8]; int i = 0; foreach (var p in AllParameters) { if (p != null) vs [i] = ((IStateManager) p).SaveViewState (); i++; } foreach (object o in vs) if (o != null) return vs; return null; } protected virtual void TrackViewState () { tracking = true; foreach (var p in AllParameters) if (p != null) ((IStateManager) p).TrackViewState (); } #endregion #region Events and Overridable Event Handler Invocations [MonoTODO] public event EventHandler ContextCreated; [MonoTODO] public event EventHandler ContextCreating; [MonoTODO] public event EventHandler ContextDisposing; [MonoTODO] public event EventHandler Deleted; [MonoTODO] public event EventHandler Deleting; [MonoTODO] internal event EventHandler Exception; [MonoTODO] public event EventHandler Inserted; [MonoTODO] public event EventHandler Inserting; [MonoTODO] public event EventHandler Selected; [MonoTODO] public event EventHandler Selecting; [MonoTODO] public event EventHandler Updated; [MonoTODO] public event EventHandler Updating; protected virtual void OnContextCreated (LinqDataSourceStatusEventArgs e) { if (ContextCreated != null) ContextCreated (this, e); } protected virtual void OnContextCreating (LinqDataSourceContextEventArgs e) { if (ContextCreating != null) ContextCreating (this, e); } protected virtual void OnContextDisposing (LinqDataSourceDisposeEventArgs e) { if (ContextDisposing != null) ContextDisposing (this, e); } protected virtual void OnDeleted (LinqDataSourceStatusEventArgs e) { if (Deleted != null) Deleted (this, e); } protected virtual void OnDeleting (LinqDataSourceDeleteEventArgs e) { if (Deleting != null) Deleting (this, e); } protected virtual void OnException (DynamicValidatorEventArgs e) { if (Exception != null) Exception (this, e); } protected virtual void OnInserted (LinqDataSourceStatusEventArgs e) { if (Inserted != null) Inserted (this, e); } protected virtual void OnInserting (LinqDataSourceInsertEventArgs e) { if (Inserting != null) Inserting (this, e); } protected virtual void OnSelected (LinqDataSourceStatusEventArgs e) { if (Selected != null) Selected (this, e); } protected virtual void OnSelecting (LinqDataSourceSelectEventArgs e) { if (Selecting != null) Selecting (this, e); } protected virtual void OnUpdated (LinqDataSourceStatusEventArgs e) { if (Updated != null) Updated (this, e); } protected virtual void OnUpdating (LinqDataSourceUpdateEventArgs e) { if (Updating != null) Updating (this, e); } #endregion } }