MetaTable.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / DynamicData / DynamicData / MetaTable.cs / 1305376 / MetaTable.cs

                            using System.Collections; 
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel; 
using System.ComponentModel.DataAnnotations;
using System.Diagnostics; 
using System.Diagnostics.CodeAnalysis; 
using System.Globalization;
using System.Linq; 
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Principal;
using System.Web.DynamicData.ModelProviders; 
using System.Web.DynamicData.Util;
using System.Web.Resources; 
using System.Web.Routing; 
using System.Web.UI;
using System.Web.UI.WebControls; 
using AttributeCollection = System.ComponentModel.AttributeCollection;

namespace System.Web.DynamicData {
    ///  
    /// Represents a database table for use by dynamic data pages
    ///  
    public class MetaTable : IMetaTable { 
        private const int DefaultColumnOrder = 10000;
        private Dictionary _columnsByName; 
        private HttpContextBase _context;
        private MetaColumn _displayColumn;
        private string _foreignKeyColumnsNames;
        private bool? _hasToStringOverride; 
        private MetaTableMetadata _metadata;
        private ReadOnlyCollection _primaryKeyColumns; 
        private string[] _primaryKeyColumnNames; 
        private bool _scaffoldDefaultValue;
        private MetaColumn _sortColumn; 
        private bool _sortColumnProcessed;
        private TableProvider _tableProvider;
        private string _listActionPath;
 
        /// 
        /// A collection of attributes declared on this entity type (i.e. class-level attributes). 
        ///  
        public AttributeCollection Attributes {
            get { 
                return Metadata.Attributes;
            }
        }
 
        /// 
        /// All columns 
        ///  
        public ReadOnlyCollection Columns {
            get; 
            // internal for unit testing
            internal set;
        }
 
        // for unit testing
        internal HttpContextBase Context { 
            private get { 
                return _context ?? new HttpContextWrapper(HttpContext.Current);
            } 
            set {
                _context = value;
            }
        } 

        ///  
        /// Name of table coming from the property on the data context. E.g. the value is "Products" for a table that is part of 
        /// the NorthwindDataContext.Products collection.
        ///  
        public string DataContextPropertyName {
            get {
                return _tableProvider.DataContextPropertyName;
            } 
        }
 
        ///  
        /// The type of the data context this table belongs to.
        ///  
        public Type DataContextType {
            get {
                return Provider.DataModel.ContextType;
            } 
        }
 
        ///  
        /// Returns the column being used for display values when entries in this table are used as parents in foreign key relationships.
        /// Which column to use can be specified using DisplayColumnAttribute. If the attribute is not present, the following heuristic is used: 
        /// 1. First non-PK string column
        /// 2. First PK string column
        /// 3. First PK non-string column
        /// 4. First column 
        /// 
        public virtual MetaColumn DisplayColumn { 
            get { 
                // use a local to avoid a null value if ResetMetadata gets called
                var displayColumn = _displayColumn; 
                if (displayColumn == null) {
                    displayColumn = GetDisplayColumnFromMetadata() ?? GetDisplayColumnFromHeuristic();
                    _displayColumn = displayColumn;
                } 

                return displayColumn; 
            } 
        }
 
        /// 
        /// Gets the string to be user-friendly string representing this table. Defaults to the value of the Name property.
        /// Can be customized using DisplayNameAttribute.
        ///  
        [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
            Justification = "Interface denotes existence of property, not used for security.")] 
        public virtual string DisplayName { 
            get {
                return Metadata.DisplayName ?? Name; 
            }
        }

        ///  
        /// Return the type of the Entity represented by this table (e.g. Product)
        ///  
        public Type EntityType { 
            get {
                return Provider.EntityType; 
            }
        }

        ///  
        /// Get a comma separated list of foreign key names.  This is useful to set the IncludePaths on an EntityDataSource
        ///  
        public string ForeignKeyColumnsNames { 
            get {
                if (_foreignKeyColumnsNames == null) { 
                    var fkColumnNamesArray = Columns.OfType().Select(column => column.Name).ToArray();
                    _foreignKeyColumnsNames = String.Join(",", fkColumnNamesArray);
                }
 
                return _foreignKeyColumnsNames;
            } 
        } 

        ///  
        /// Returns true if the table has a primary key
        /// 
        public bool HasPrimaryKey {
            get { 
                // Some of the columns may be primary keys, but if this is a view, it doesn't "have"
                // any primary keys, so PrimaryKey is null. 
                return PrimaryKeyColumns.Count > 0; 
            }
        } 

        private bool HasToStringOverride {
            get {
                // Check if the entity type overrides ToString() 
                //
                if (!_hasToStringOverride.HasValue) { 
                    MethodInfo toStringMethod = EntityType.GetMethod("ToString"); 
                    _hasToStringOverride = (toStringMethod.DeclaringType != typeof(object));
                } 

                return _hasToStringOverride.Value;
            }
        } 

        ///  
        /// Returns true if this is a read-only table or view(has not PK). 
        /// 
        [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces", 
            Justification = "Interface denotes existence of property, not used for security.")]
        public virtual bool IsReadOnly {
            get {
                return Metadata.IsReadOnly || !HasPrimaryKey; 
            }
        } 
 
        /// 
        /// Gets the action path to the list action for this table 
        /// 
        public string ListActionPath {
            get {
                return _listActionPath ?? GetActionPath(PageAction.List); 
            }
            internal set { 
                _listActionPath = value; 
            }
        } 

        private MetaTableMetadata Metadata {
            get {
                // use a local to avoid returning null if ResetMetadata gets called 
                var metadata = _metadata;
                if (metadata == null) { 
                    metadata = new MetaTableMetadata(this); 
                    _metadata = metadata;
                } 
                return metadata;
            }
        }
 
        /// 
        /// The model this table belongs to. 
        ///  
        public MetaModel Model { get; private set; }
 
        /// 
        /// Unique name of table. This name is unique within a given data context. (e.g. "MyCustomName_Products")
        /// 
        public string Name { 
            get;
            private set; 
        } 

        ///  
        /// Columns that constitute the primary key of this table
        /// 
        public ReadOnlyCollection PrimaryKeyColumns {
            get { 
                if (_primaryKeyColumns == null) {
                    _primaryKeyColumns = Columns.Where(c => c.IsPrimaryKey).ToList().AsReadOnly(); 
                } 
                return _primaryKeyColumns;
            } 
        }

        internal string[] PrimaryKeyNames {
            get { 
                if (_primaryKeyColumnNames == null) {
                    _primaryKeyColumnNames = PrimaryKeyColumns.Select(c => c.Name).ToArray(); 
                } 
                return _primaryKeyColumnNames;
            } 
        }

        /// 
        /// The underlying provider for this column 
        /// 
        public TableProvider Provider { get { return _tableProvider; } } 
 
        /// 
        /// Return the root type of this entity's inheritance hierarchy; if the type is at the top 
        /// of an inheritance hierarchy or does not have any inheritance, will return EntityType.
        /// 
        public Type RootEntityType {
            get { 
                return Provider.RootEntityType;
            } 
        } 

        ///  
        /// Whether or not to scaffold. This can be customized using ScaffoldAttribute
        /// 
        [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
            Justification = "Interface denotes existence of property, not used for security.")] 
        public virtual bool Scaffold {
            get { 
                return Metadata.ScaffoldTable ?? _scaffoldDefaultValue; 
            }
        } 

        /// 
        /// Gets the column used as the sorting column when used FK relationships. Defaults to the same column that is returned by DisplayColumn.
        /// Can be customized using options on DisplayColumnAttribute. 
        /// 
        public virtual MetaColumn SortColumn { 
            get { 
                if (!_sortColumnProcessed) {
                    var displayColumnAttribute = Metadata.DisplayColumnAttribute; 
                    if (displayColumnAttribute != null && !String.IsNullOrEmpty(displayColumnAttribute.SortColumn)) {
                        if (!TryGetColumn(displayColumnAttribute.SortColumn, out _sortColumn)) {
                            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                                DynamicDataResources.MetaTable_CantFindSortColumn, 
                                displayColumnAttribute.SortColumn,
                                Name)); 
                        } 

                        if (_sortColumn is MetaChildrenColumn) { 
                            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                                DynamicDataResources.MetaTable_CantUseChildrenColumnAsSortColumn,
                                _sortColumn.Name,
                                Name)); 
                        }
                    } 
                    _sortColumnProcessed = true; 
                }
                return _sortColumn; 
            }
        }

        ///  
        /// Returns true if the entries in this column are meant to be sorted in a descending order when used as parents in a FK relationship.
        /// Can be declared using options on DisplayColumnAttribute 
        ///  
        [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
            Justification = "Interface denotes existence of property, not used for security.")] 
        public virtual bool SortDescending {
            get {
                return Metadata.SortDescending;
            } 
        }
 
        public MetaTable(MetaModel metaModel, TableProvider tableProvider) { 
            _tableProvider = tableProvider;
            Model = metaModel; 
        }

        /// 
        /// Build the attribute collection, made publicly available through the Attributes property 
        /// 
        protected virtual AttributeCollection BuildAttributeCollection() { 
            return Provider.Attributes; 
        }
 
        /// 
        /// Returns whether the passed in user is allowed to delete items from the table
        /// 
        public virtual bool CanDelete(IPrincipal principal) { 
            return Provider.CanDelete(principal);
        } 
 
        /// 
        /// Returns whether the passed in user is allowed to insert into the table 
        /// 
        public virtual bool CanInsert(IPrincipal principal) {
            return Provider.CanInsert(principal);
        } 

        ///  
        /// Returns whether the passed in user is allowed to read from the table 
        /// 
        public virtual bool CanRead(IPrincipal principal) { 
            return Provider.CanRead(principal);
        }

        ///  
        /// Returns whether the passed in user is allowed to make changes tothe table
        ///  
        public virtual bool CanUpdate(IPrincipal principal) { 
            return Provider.CanUpdate(principal);
        } 

        public static MetaTable CreateTable(Type entityType) {
            return MetaModel.CreateSimpleModel(entityType).Tables.First();
        } 

        public static MetaTable CreateTable(ICustomTypeDescriptor typeDescriptor) { 
            return MetaModel.CreateSimpleModel(typeDescriptor).Tables.First(); 
        }
 
        /// 
        /// Instantiate a MetaChildrenColumn object. Can be overridden to instantiate a derived type
        /// 
        ///  
        protected virtual MetaChildrenColumn CreateChildrenColumn(ColumnProvider columnProvider) {
            return new MetaChildrenColumn(this, columnProvider); 
        } 

        ///  
        /// Instantiate a MetaColumn object. Can be overridden to instantiate a derived type
        /// 
        /// 
        protected virtual MetaColumn CreateColumn(ColumnProvider columnProvider) { 
            return new MetaColumn(this, columnProvider);
        } 
 
        private MetaColumn CreateColumnInternal(ColumnProvider columnProvider) {
            if (columnProvider.Association != null) { 
                switch (columnProvider.Association.Direction) {
                    case AssociationDirection.OneToOne:
                    case AssociationDirection.ManyToOne:
                        return CreateForeignKeyColumn(columnProvider); 
                    case AssociationDirection.ManyToMany:
                    case AssociationDirection.OneToMany: 
                        return CreateChildrenColumn(columnProvider); 
                }
                Debug.Assert(false); 
            }

            return CreateColumn(columnProvider);
        } 

        internal void CreateColumns() { 
            var columns = new List(); 

            foreach (ColumnProvider columnProvider in Provider.Columns) { 
                MetaColumn column = CreateColumnInternal(columnProvider);
                columns.Add(column);
            }
 
            Columns = new ReadOnlyCollection(columns);
            _columnsByName = Columns.ToDictionary(c => c.Name, StringComparer.OrdinalIgnoreCase); 
        } 

        ///  
        /// Instantiate a data context that this table belongs to. Uses the instatiotion method specified when the context was registered.
        /// 
        /// 
        public virtual object CreateContext() { 
            return Provider.DataModel.CreateContext();
        } 
 
        /// 
        /// Instantiate a MetaForeignKeyColumn object. Can be overridden to instantiate a derived type 
        /// 
        /// 
        protected virtual MetaForeignKeyColumn CreateForeignKeyColumn(ColumnProvider columnProvider) {
            return new MetaForeignKeyColumn(this, columnProvider); 
        }
 
        ///  
        /// Gets the action path for the given row (to get primary key values for query string filters, etc.)
        ///  
        /// 
        /// the instance of the row
        /// 
        public string GetActionPath(string action, object row) { 
            // Delegate to the overload that takes an array of primary key values
            return GetActionPath(action, GetPrimaryKeyValues(row)); 
        } 

        ///  
        /// Gets the action path for the given row (to get primary key values for query string filters, etc.)
        /// 
        /// 
        /// the instance of the row 
        /// 
        ///  
        public string GetActionPath(string action, object row, string path) { 
            // Delegate to the overload that takes an array of primary key values
            return GetActionPath(action, GetPrimaryKeyValues(row), path); 
        }

        /// 
        /// Gets the action path for the current table and the passed in action 
        /// 
        public string GetActionPath(string action) { 
            return GetActionPath(action, (IList)null); 
        }
 
        /// 
        /// Gets the action path for the current table and the passed in action. Also, include all the passed in
        /// route values in the path
        ///  
        /// 
        public string GetActionPath(string action, RouteValueDictionary routeValues) { 
            routeValues.Add(DynamicDataRoute.TableToken, Name); 
            routeValues.Add(DynamicDataRoute.ActionToken, action);
 
            // Try to get the path from the route
            return GetActionPathFromRoutes(routeValues);
        }
 
        /// 
        /// Gets the action path for the current table and the passed in action. Also, include the passed in 
        /// primary key as part of the route. 
        /// 
        ///  
        public string GetActionPath(string action, IList primaryKeyValues) {
            var routeValues = new RouteValueDictionary();
            routeValues.Add(DynamicDataRoute.TableToken, Name);
            routeValues.Add(DynamicDataRoute.ActionToken, action); 

            GetRouteValuesFromPK(routeValues, primaryKeyValues); 
 
            // Try to get the path from the route
            return GetActionPathFromRoutes(routeValues); 
        }

        /// 
        /// Use the passed in path and append to it query string parameters for the passed in primary key values 
        /// 
        public string GetActionPath(string action, IList primaryKeyValues, string path) { 
 
            // If there is no path, use standard routing
            if (String.IsNullOrEmpty(path)) { 
                return GetActionPath(action, primaryKeyValues);
            }

            // Get all the PK values in a dictionary 
            var routeValues = new RouteValueDictionary();
            GetRouteValuesFromPK(routeValues, primaryKeyValues); 
 
            // Create a query string from it and Add it to the path
            return QueryStringHandler.AddFiltersToPath(path, routeValues); 
        }

        private string GetActionPathFromRoutes(RouteValueDictionary routeValues) {
            RequestContext requestContext = DynamicDataRouteHandler.GetRequestContext(Context); 
            string path = null;
 
            if (requestContext != null) { 
                // Add the model to the route values so that the route can make sure it only
                // gets matched if it is meant to work with that model 
                routeValues.Add(DynamicDataRoute.ModelToken, Model);

                VirtualPathData vpd = RouteTable.Routes.GetVirtualPath(requestContext, routeValues);
                if (vpd != null) { 
                    path = vpd.VirtualPath;
                } 
            } 

            // If the virtual path is null, then there is no page to link to 
            return path ?? String.Empty;
        }

        ///  
        /// Looks up a column by the given name. If no column is found, an exception is thrown.
        ///  
        ///  
        /// 
        public MetaColumn GetColumn(string columnName) { 
            MetaColumn column;
            if (!TryGetColumn(columnName, out column)) {
                throw new InvalidOperationException(String.Format(
                    CultureInfo.CurrentCulture, 
                    DynamicDataResources.MetaTable_NoSuchColumn,
                    Name, 
                    columnName)); 
            }
            return column; 
        }

        private static int GetColumnOrder(MetaColumn column) {
            var displayAttribute = column.Metadata.DisplayAttribute; 
            if (displayAttribute != null && displayAttribute.GetOrder() != null) {
                return displayAttribute.GetOrder().Value; 
            } 

            return DefaultColumnOrder; 
        }

        private static int GetColumnOrder(MetaColumn column, IDictionary groupings) {
            var displayAttribute = column.Metadata.DisplayAttribute; 
            int order;
            if (displayAttribute != null) { 
                string groupName = displayAttribute.GetGroupName(); 
                if (!String.IsNullOrEmpty(groupName) && groupings.TryGetValue(groupName, out order)) {
                    return order; 
                }
            }

            return GetColumnOrder(column); 
        }
 
        ///  
        /// Look for this table's primary key in the route values (i.e. typically the query string).
        /// If they're all found, return a DataKey containing the primary key values. Otherwise return null. 
        /// 
        public DataKey GetDataKeyFromRoute() {
            var queryStringKeys = new OrderedDictionary(PrimaryKeyNames.Length);
            foreach (MetaColumn key in PrimaryKeyColumns) { 
                // Try to find the PK in the route values. If any PK is not found, return null
                string value = Misc.GetRouteValue(key.Name); 
                if (string.IsNullOrEmpty(value)) 
                    return null;
 
                queryStringKeys[key.Name] = Misc.ChangeType(value, key.ColumnType);
            }

            return new DataKey(queryStringKeys, PrimaryKeyNames); 
        }
 
        private MetaColumn GetDisplayColumnFromHeuristic() { 
            // Pick best available option (except for columns based on custom properties)
            // 1. First non-PK string column 
            // 2. First PK string column
            // 3. First PK non-string column
            // 4. First column (from all columns)
            var serverSideColumns = Columns.Where(c => !c.IsCustomProperty).ToList(); 

            return serverSideColumns.FirstOrDefault(c => c.IsString && !c.IsPrimaryKey) ?? 
                serverSideColumns.FirstOrDefault(c => c.IsString) ?? 
                serverSideColumns.FirstOrDefault(c => c.IsPrimaryKey) ??
                Columns.First(); 
        }

        private MetaColumn GetDisplayColumnFromMetadata() {
            var displayColumnAttribute = Metadata.DisplayColumnAttribute; 
            if (displayColumnAttribute == null) {
                return null; 
            } 

            MetaColumn displayColumn = null; 
            if (!TryGetColumn(displayColumnAttribute.DisplayColumn, out displayColumn)) {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                    DynamicDataResources.MetaTable_CantFindDisplayColumn,
                    displayColumnAttribute.DisplayColumn, 
                    Name));
            } 
 
            return displayColumn;
        } 

        /// 
        /// Gets the value to be used as the display string for an instance of a row of this table when used in FK relationships.
        /// If the row is null, returns an empty string. If the entity class has an overidden ToString() method, returns the result 
        /// of that method. Otherwise, returns the ToString representation of the value of the display column (as returned by the DisplayColumn
        /// property) for the given row. 
        ///  
        /// the instance of the row
        ///  
        public virtual string GetDisplayString(object row) {
            if (row == null)
                return String.Empty;
 
            // Make sure it's of the right type, and handle collections
            row = PreprocessRowObject(row); 
 
            // If there is a ToString() override, use it
            if (HasToStringOverride) { 
                return row.ToString();
            }

            // Otherwise, use the 'display column' 
            object displayObject = DataBinder.GetPropertyValue(row, DisplayColumn.Name);
            return displayObject == null ? String.Empty : displayObject.ToString(); 
        } 

        ///  
        /// Returns an enumeration of columns that are filterable by default. A column is filterable if it
        /// 
    ///
  • is decorated with FilterAttribte with Enabled=true
  • ///
  • is scaffold, is not a custom property, and is either a FK column or a Bool column
  • ///
/// The enumeration is ordered by the value of the FilterAttribute.Order property. If a column /// does not have that attribute, the value 0 is used. ///
/// public virtual IEnumerable GetFilteredColumns() { IDictionary columnGroupOrder = GetColumnGroupingOrder(); return Columns.Where(c => IsFilterableColumn(c, Context.User)) .OrderBy(c => GetColumnOrder(c, columnGroupOrder)) .ThenBy(c => GetColumnOrder(c)); } private IDictionary GetColumnGroupingOrder() { // Group columns that have groups by group names. Then put them into a dictionary from group name -> // minimum column order so that groups are "stick" close together. return Columns.Where(c => c.Metadata.DisplayAttribute != null && !String.IsNullOrEmpty(c.Metadata.DisplayAttribute.GetGroupName())) .GroupBy(c => c.Metadata.DisplayAttribute.GetGroupName()) .ToDictionary(cg => cg.Key, cg => cg.Min(c => GetColumnOrder(c))); } /// /// Get a dictionary of primary key names and their values for the given row instance /// /// /// public IDictionary GetPrimaryKeyDictionary(object row) { row = PreprocessRowObject(row); Dictionary result = new Dictionary(); foreach (MetaColumn pkMember in PrimaryKeyColumns) { result.Add(pkMember.Name, DataBinder.GetPropertyValue(row, pkMember.Name)); } return result; } /// /// Get a comma separated list of values representing the primary key for the given row instance /// /// /// public string GetPrimaryKeyString(object row) { // Make sure it's of the right type, and handle collections row = PreprocessRowObject(row); return GetPrimaryKeyString(GetPrimaryKeyValues(row)); } /// /// Get a comma separated list of values representing the primary key /// /// /// public string GetPrimaryKeyString(IList primaryKeyValues) { return Misc.PersistListToCommaSeparatedString(primaryKeyValues); } /// /// Get the value of the primary key components for a given row /// /// /// public IList GetPrimaryKeyValues(object row) { if (row == null) return null; // Make sure it's of the right type, and handle collections row = PreprocessRowObject(row); return Misc.GetKeyValues(PrimaryKeyColumns, row); } /// /// Get the IQueryable for the entity type represented by this table (i.e. IQueryable of Product). Retrieves it from a new context /// instantiated using the CreateContext(). /// /// public IQueryable GetQuery() { return GetQuery(null); } /// /// Get the IQueryable for the entity type represented by this table (i.e. IQueryable of Product). Retrieves it from the provided /// context instance, or instantiates a new context using the CreateContext(). /// /// /// public virtual IQueryable GetQuery(object context) { if (context == null) { context = CreateContext(); } IQueryable query = Provider.GetQuery(context); if (EntityType != RootEntityType) { Expression ofTypeExpression = Expression.Call(typeof(Queryable), "OfType", new[] { EntityType }, query.Expression); query = query.Provider.CreateQuery(ofTypeExpression); } // Return the sorted query if there is a sort column if (SortColumn != null) { return Misc.BuildSortQueryable(query, this); } return query; } private void GetRouteValuesFromPK(RouteValueDictionary routeValues, IList primaryKeyValues) { if (primaryKeyValues != null) { for (int i = 0; i < PrimaryKeyNames.Length; i++) { routeValues.Add(PrimaryKeyNames[i], Misc.SanitizeQueryStringValue(primaryKeyValues[i])); } } } /// /// Returns an enumeration of columns that are to be displayed in a scaffolded context. By default all columns with the Scaffold /// property set to true are included, with the exception of: ///
    ///
  • Long-string columns (IsLongString property set to true) when the inListControl flag is true
  • ///
  • Children columns when mode is equal to Insert
  • ///
///
/// The mode, such as ReadOnly, Edit, or Insert. /// A flag indicating if the table is being displayed as an individual entity or as part of list-grid. /// public virtual IEnumerable GetScaffoldColumns(DataBoundControlMode mode, ContainerType containerType) { IDictionary columnGroupOrder = GetColumnGroupingOrder(); return Columns.Where(c => IsScaffoldColumn(c, mode, containerType)) .OrderBy(c => GetColumnOrder(c, columnGroupOrder)) .ThenBy(c => GetColumnOrder(c)); } /// /// Gets the table associated with the given type, regardless of which model it belongs to. /// public static MetaTable GetTable(Type entityType) { MetaTable table; if (!TryGetTable(entityType, out table)) { throw new InvalidOperationException(String.Format( CultureInfo.CurrentCulture, DynamicDataResources.MetaModel_EntityTypeDoesNotBelongToModel, entityType.FullName)); } return table; } /// /// Perform initialization logic for this table /// internal protected virtual void Initialize() { foreach (MetaColumn column in Columns) { column.Initialize(); } } internal static bool IsFilterableColumn(IMetaColumn column, IPrincipal user) { Debug.Assert(column != null); var displayAttribute = column.Attributes.FirstOrDefault(); if (displayAttribute != null && displayAttribute.GetAutoGenerateFilter().HasValue) { return displayAttribute.GetAutoGenerateFilter().Value; } if (!String.IsNullOrEmpty(column.FilterUIHint)) { return true; } // non-scaffolded columns should not be displayed by default if (!column.Scaffold) { return false; } // custom properties won't be queryable by the server if (column.IsCustomProperty) { return false; } var fkColumn = column as IMetaForeignKeyColumn; if (fkColumn != null) { // Only allow if the user has access to the parent table return fkColumn.ParentTable.CanRead(user); } if (column.ColumnType == typeof(bool)) { return true; } if (column.GetEnumType() != null) { return true; } return false; } private bool IsScaffoldColumn(IMetaColumn column, DataBoundControlMode mode, ContainerType containerType) { if (!column.Scaffold) { return false; } // Children columns don't make sense for new rows, so ignore them in Insert mode if ((mode == DataBoundControlMode.Insert) && (column is IMetaChildrenColumn)) { return false; } var fkColumn = column as IMetaForeignKeyColumn; if (fkColumn != null) { // Ignore the FK column if the user doesn't have access to the parent table if (!fkColumn.ParentTable.CanRead(Context.User)) { return false; } } return true; } public IDictionary GetColumnValuesFromRoute(HttpContext context) { return GetColumnValuesFromRoute(context.ToWrapper()); } internal IDictionary GetColumnValuesFromRoute(HttpContextBase context) { RouteValueDictionary routeValues = DynamicDataRouteHandler.GetRequestContext(context).RouteData.Values; Dictionary columnValues = new Dictionary(); foreach (var column in Columns) { if (Misc.IsColumnInDictionary(column, routeValues)) { MetaForeignKeyColumn foreignKeyColumn = column as MetaForeignKeyColumn; if (foreignKeyColumn != null) { // Add all the foreign keys to the column values. foreach (var fkName in foreignKeyColumn.ForeignKeyNames) { columnValues[fkName] = routeValues[fkName]; } } else { // Convert the value to the correct type. columnValues[column.Name] = Misc.ChangeType(routeValues[column.Name], column.ColumnType); } } } return columnValues; } private object PreprocessRowObject(object row) { // If null, nothing to do if (row == null) return null; // If it's of the correct entity type, we're done if (EntityType.IsAssignableFrom(row.GetType())) { return row; } // If it's a list, try using the first item var rowCollection = row as IList; if (rowCollection != null) { if (rowCollection.Count >= 1) { Debug.Assert(rowCollection.Count == 1); return PreprocessRowObject(rowCollection[0]); } } // We didn't recoginze the object, so return it unchanged return row; } /// /// Resets cached table metadata (i.e. information coming from attributes) as well as metadata of all columns. /// The metadata cache will be rebuilt the next time any metadata-derived information gets requested. /// public void ResetMetadata() { _metadata = null; _displayColumn = null; _sortColumnProcessed = false; foreach (var column in Columns) { column.ResetMetadata(); } } internal void SetScaffoldAndName(bool scaffoldDefaultValue, string nameOverride) { if (!String.IsNullOrEmpty(nameOverride)) { Name = nameOverride; } else if (Provider != null) { Name = Provider.Name; } _scaffoldDefaultValue = scaffoldDefaultValue; } /// /// /// /// [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] public override string ToString() { return Name; } /// /// Tries to find a column by the given name. If a column is found, it is assigned to the column /// variable and the method returns true. Otherwise, it returns false and column is null. /// /// /// /// public bool TryGetColumn(string columnName, out MetaColumn column) { if (columnName == null) { throw new ArgumentNullException("columnName"); } return _columnsByName.TryGetValue(columnName, out column); } /// /// Gets the table associated with the given type, regardless of which model it belongs to. /// public static bool TryGetTable(Type entityType, out MetaTable table) { MetaModel.CheckForRegistrationException(); if (entityType == null) { throw new ArgumentNullException("entityType"); } return System.Web.DynamicData.MetaModel.MetaModelManager.TryGetTable(entityType, out table); } #region IMetaTable Members string[] IMetaTable.PrimaryKeyNames { get { return PrimaryKeyNames; } } object IMetaTable.CreateContext() { return CreateContext(); } string IMetaTable.GetDisplayString(object row) { return GetDisplayString(row); } IQueryable IMetaTable.GetQuery(object context) { return GetQuery(context); } #endregion private class MetaTableMetadata { private DisplayNameAttribute _displayNameAttribute; private ReadOnlyAttribute _readOnlyAttribute; public MetaTableMetadata(MetaTable table) { Debug.Assert(table != null); Attributes = table.BuildAttributeCollection(); _readOnlyAttribute = Attributes.FirstOrDefault(); _displayNameAttribute = Attributes.FirstOrDefault(); DisplayColumnAttribute = Attributes.FirstOrDefault(); ScaffoldTable = Attributes.GetAttributePropertyValue(a => a.Scaffold, null); } public AttributeCollection Attributes { get; private set; } public DisplayColumnAttribute DisplayColumnAttribute { get; private set; } public string DisplayName { get { return _displayNameAttribute.GetPropertyValue(a => a.DisplayName, null); } } public bool? ScaffoldTable { get; private set; } public bool SortDescending { get { return DisplayColumnAttribute.GetPropertyValue(a => a.SortDescending, false); } } public bool IsReadOnly { get { return _readOnlyAttribute.GetPropertyValue(a => a.IsReadOnly, false); } } } ReadOnlyCollection IMetaTable.Columns { get { // Covariance only supported on interfaces return Columns.OfType().ToList().AsReadOnly(); } } IMetaModel IMetaTable.Model { get { return Model; } } IMetaColumn IMetaTable.DisplayColumn { get { return DisplayColumn; } } IMetaColumn IMetaTable.GetColumn(string columnName) { return GetColumn(columnName); } IEnumerable IMetaTable.GetFilteredColumns() { // We can remove the of type when we get rid of the Vnext solution since interface covariance support // was only added in 4.0 return GetFilteredColumns().OfType(); } IEnumerable IMetaTable.GetScaffoldColumns(DataBoundControlMode mode, ContainerType containerType) { // We can remove the of type when we get rid of the Vnext solution since interface covariance support // was only added in 4.0 return GetScaffoldColumns(mode, containerType).OfType(); } ReadOnlyCollection IMetaTable.PrimaryKeyColumns { get { return PrimaryKeyColumns.OfType().ToList().AsReadOnly(); } } IMetaColumn IMetaTable.SortColumn { get { return SortColumn; } } bool IMetaTable.TryGetColumn(string columnName, out IMetaColumn column) { MetaColumn metaColumn; column = null; if (TryGetColumn(columnName, out metaColumn)) { column = metaColumn; return true; } return false; } bool IMetaTable.CanDelete(IPrincipal principal) { return CanDelete(principal); } bool IMetaTable.CanInsert(IPrincipal principal) { return CanInsert(principal); } bool IMetaTable.CanRead(IPrincipal principal) { return CanRead(principal); } bool IMetaTable.CanUpdate(IPrincipal principal) { return CanUpdate(principal); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Security.Principal; using System.Web.DynamicData.ModelProviders; using System.Web.DynamicData.Util; using System.Web.Resources; using System.Web.Routing; using System.Web.UI; using System.Web.UI.WebControls; using AttributeCollection = System.ComponentModel.AttributeCollection; namespace System.Web.DynamicData { /// /// Represents a database table for use by dynamic data pages /// public class MetaTable : IMetaTable { private const int DefaultColumnOrder = 10000; private Dictionary _columnsByName; private HttpContextBase _context; private MetaColumn _displayColumn; private string _foreignKeyColumnsNames; private bool? _hasToStringOverride; private MetaTableMetadata _metadata; private ReadOnlyCollection _primaryKeyColumns; private string[] _primaryKeyColumnNames; private bool _scaffoldDefaultValue; private MetaColumn _sortColumn; private bool _sortColumnProcessed; private TableProvider _tableProvider; private string _listActionPath; /// /// A collection of attributes declared on this entity type (i.e. class-level attributes). /// public AttributeCollection Attributes { get { return Metadata.Attributes; } } /// /// All columns /// public ReadOnlyCollection Columns { get; // internal for unit testing internal set; } // for unit testing internal HttpContextBase Context { private get { return _context ?? new HttpContextWrapper(HttpContext.Current); } set { _context = value; } } /// /// Name of table coming from the property on the data context. E.g. the value is "Products" for a table that is part of /// the NorthwindDataContext.Products collection. /// public string DataContextPropertyName { get { return _tableProvider.DataContextPropertyName; } } /// /// The type of the data context this table belongs to. /// public Type DataContextType { get { return Provider.DataModel.ContextType; } } /// /// Returns the column being used for display values when entries in this table are used as parents in foreign key relationships. /// Which column to use can be specified using DisplayColumnAttribute. If the attribute is not present, the following heuristic is used: /// 1. First non-PK string column /// 2. First PK string column /// 3. First PK non-string column /// 4. First column /// public virtual MetaColumn DisplayColumn { get { // use a local to avoid a null value if ResetMetadata gets called var displayColumn = _displayColumn; if (displayColumn == null) { displayColumn = GetDisplayColumnFromMetadata() ?? GetDisplayColumnFromHeuristic(); _displayColumn = displayColumn; } return displayColumn; } } /// /// Gets the string to be user-friendly string representing this table. Defaults to the value of the Name property. /// Can be customized using DisplayNameAttribute. /// [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces", Justification = "Interface denotes existence of property, not used for security.")] public virtual string DisplayName { get { return Metadata.DisplayName ?? Name; } } /// /// Return the type of the Entity represented by this table (e.g. Product) /// public Type EntityType { get { return Provider.EntityType; } } /// /// Get a comma separated list of foreign key names. This is useful to set the IncludePaths on an EntityDataSource /// public string ForeignKeyColumnsNames { get { if (_foreignKeyColumnsNames == null) { var fkColumnNamesArray = Columns.OfType().Select(column => column.Name).ToArray(); _foreignKeyColumnsNames = String.Join(",", fkColumnNamesArray); } return _foreignKeyColumnsNames; } } /// /// Returns true if the table has a primary key /// public bool HasPrimaryKey { get { // Some of the columns may be primary keys, but if this is a view, it doesn't "have" // any primary keys, so PrimaryKey is null. return PrimaryKeyColumns.Count > 0; } } private bool HasToStringOverride { get { // Check if the entity type overrides ToString() // if (!_hasToStringOverride.HasValue) { MethodInfo toStringMethod = EntityType.GetMethod("ToString"); _hasToStringOverride = (toStringMethod.DeclaringType != typeof(object)); } return _hasToStringOverride.Value; } } /// /// Returns true if this is a read-only table or view(has not PK). /// [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces", Justification = "Interface denotes existence of property, not used for security.")] public virtual bool IsReadOnly { get { return Metadata.IsReadOnly || !HasPrimaryKey; } } /// /// Gets the action path to the list action for this table /// public string ListActionPath { get { return _listActionPath ?? GetActionPath(PageAction.List); } internal set { _listActionPath = value; } } private MetaTableMetadata Metadata { get { // use a local to avoid returning null if ResetMetadata gets called var metadata = _metadata; if (metadata == null) { metadata = new MetaTableMetadata(this); _metadata = metadata; } return metadata; } } /// /// The model this table belongs to. /// public MetaModel Model { get; private set; } /// /// Unique name of table. This name is unique within a given data context. (e.g. "MyCustomName_Products") /// public string Name { get; private set; } /// /// Columns that constitute the primary key of this table /// public ReadOnlyCollection PrimaryKeyColumns { get { if (_primaryKeyColumns == null) { _primaryKeyColumns = Columns.Where(c => c.IsPrimaryKey).ToList().AsReadOnly(); } return _primaryKeyColumns; } } internal string[] PrimaryKeyNames { get { if (_primaryKeyColumnNames == null) { _primaryKeyColumnNames = PrimaryKeyColumns.Select(c => c.Name).ToArray(); } return _primaryKeyColumnNames; } } /// /// The underlying provider for this column /// public TableProvider Provider { get { return _tableProvider; } } /// /// Return the root type of this entity's inheritance hierarchy; if the type is at the top /// of an inheritance hierarchy or does not have any inheritance, will return EntityType. /// public Type RootEntityType { get { return Provider.RootEntityType; } } /// /// Whether or not to scaffold. This can be customized using ScaffoldAttribute /// [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces", Justification = "Interface denotes existence of property, not used for security.")] public virtual bool Scaffold { get { return Metadata.ScaffoldTable ?? _scaffoldDefaultValue; } } /// /// Gets the column used as the sorting column when used FK relationships. Defaults to the same column that is returned by DisplayColumn. /// Can be customized using options on DisplayColumnAttribute. /// public virtual MetaColumn SortColumn { get { if (!_sortColumnProcessed) { var displayColumnAttribute = Metadata.DisplayColumnAttribute; if (displayColumnAttribute != null && !String.IsNullOrEmpty(displayColumnAttribute.SortColumn)) { if (!TryGetColumn(displayColumnAttribute.SortColumn, out _sortColumn)) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DynamicDataResources.MetaTable_CantFindSortColumn, displayColumnAttribute.SortColumn, Name)); } if (_sortColumn is MetaChildrenColumn) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DynamicDataResources.MetaTable_CantUseChildrenColumnAsSortColumn, _sortColumn.Name, Name)); } } _sortColumnProcessed = true; } return _sortColumn; } } /// /// Returns true if the entries in this column are meant to be sorted in a descending order when used as parents in a FK relationship. /// Can be declared using options on DisplayColumnAttribute /// [SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces", Justification = "Interface denotes existence of property, not used for security.")] public virtual bool SortDescending { get { return Metadata.SortDescending; } } public MetaTable(MetaModel metaModel, TableProvider tableProvider) { _tableProvider = tableProvider; Model = metaModel; } /// /// Build the attribute collection, made publicly available through the Attributes property /// protected virtual AttributeCollection BuildAttributeCollection() { return Provider.Attributes; } /// /// Returns whether the passed in user is allowed to delete items from the table /// public virtual bool CanDelete(IPrincipal principal) { return Provider.CanDelete(principal); } /// /// Returns whether the passed in user is allowed to insert into the table /// public virtual bool CanInsert(IPrincipal principal) { return Provider.CanInsert(principal); } /// /// Returns whether the passed in user is allowed to read from the table /// public virtual bool CanRead(IPrincipal principal) { return Provider.CanRead(principal); } /// /// Returns whether the passed in user is allowed to make changes tothe table /// public virtual bool CanUpdate(IPrincipal principal) { return Provider.CanUpdate(principal); } public static MetaTable CreateTable(Type entityType) { return MetaModel.CreateSimpleModel(entityType).Tables.First(); } public static MetaTable CreateTable(ICustomTypeDescriptor typeDescriptor) { return MetaModel.CreateSimpleModel(typeDescriptor).Tables.First(); } /// /// Instantiate a MetaChildrenColumn object. Can be overridden to instantiate a derived type /// /// protected virtual MetaChildrenColumn CreateChildrenColumn(ColumnProvider columnProvider) { return new MetaChildrenColumn(this, columnProvider); } /// /// Instantiate a MetaColumn object. Can be overridden to instantiate a derived type /// /// protected virtual MetaColumn CreateColumn(ColumnProvider columnProvider) { return new MetaColumn(this, columnProvider); } private MetaColumn CreateColumnInternal(ColumnProvider columnProvider) { if (columnProvider.Association != null) { switch (columnProvider.Association.Direction) { case AssociationDirection.OneToOne: case AssociationDirection.ManyToOne: return CreateForeignKeyColumn(columnProvider); case AssociationDirection.ManyToMany: case AssociationDirection.OneToMany: return CreateChildrenColumn(columnProvider); } Debug.Assert(false); } return CreateColumn(columnProvider); } internal void CreateColumns() { var columns = new List(); foreach (ColumnProvider columnProvider in Provider.Columns) { MetaColumn column = CreateColumnInternal(columnProvider); columns.Add(column); } Columns = new ReadOnlyCollection(columns); _columnsByName = Columns.ToDictionary(c => c.Name, StringComparer.OrdinalIgnoreCase); } /// /// Instantiate a data context that this table belongs to. Uses the instatiotion method specified when the context was registered. /// /// public virtual object CreateContext() { return Provider.DataModel.CreateContext(); } /// /// Instantiate a MetaForeignKeyColumn object. Can be overridden to instantiate a derived type /// /// protected virtual MetaForeignKeyColumn CreateForeignKeyColumn(ColumnProvider columnProvider) { return new MetaForeignKeyColumn(this, columnProvider); } /// /// Gets the action path for the given row (to get primary key values for query string filters, etc.) /// /// /// the instance of the row /// public string GetActionPath(string action, object row) { // Delegate to the overload that takes an array of primary key values return GetActionPath(action, GetPrimaryKeyValues(row)); } /// /// Gets the action path for the given row (to get primary key values for query string filters, etc.) /// /// /// the instance of the row /// /// public string GetActionPath(string action, object row, string path) { // Delegate to the overload that takes an array of primary key values return GetActionPath(action, GetPrimaryKeyValues(row), path); } /// /// Gets the action path for the current table and the passed in action /// public string GetActionPath(string action) { return GetActionPath(action, (IList)null); } /// /// Gets the action path for the current table and the passed in action. Also, include all the passed in /// route values in the path /// /// public string GetActionPath(string action, RouteValueDictionary routeValues) { routeValues.Add(DynamicDataRoute.TableToken, Name); routeValues.Add(DynamicDataRoute.ActionToken, action); // Try to get the path from the route return GetActionPathFromRoutes(routeValues); } /// /// Gets the action path for the current table and the passed in action. Also, include the passed in /// primary key as part of the route. /// /// public string GetActionPath(string action, IList primaryKeyValues) { var routeValues = new RouteValueDictionary(); routeValues.Add(DynamicDataRoute.TableToken, Name); routeValues.Add(DynamicDataRoute.ActionToken, action); GetRouteValuesFromPK(routeValues, primaryKeyValues); // Try to get the path from the route return GetActionPathFromRoutes(routeValues); } /// /// Use the passed in path and append to it query string parameters for the passed in primary key values /// public string GetActionPath(string action, IList primaryKeyValues, string path) { // If there is no path, use standard routing if (String.IsNullOrEmpty(path)) { return GetActionPath(action, primaryKeyValues); } // Get all the PK values in a dictionary var routeValues = new RouteValueDictionary(); GetRouteValuesFromPK(routeValues, primaryKeyValues); // Create a query string from it and Add it to the path return QueryStringHandler.AddFiltersToPath(path, routeValues); } private string GetActionPathFromRoutes(RouteValueDictionary routeValues) { RequestContext requestContext = DynamicDataRouteHandler.GetRequestContext(Context); string path = null; if (requestContext != null) { // Add the model to the route values so that the route can make sure it only // gets matched if it is meant to work with that model routeValues.Add(DynamicDataRoute.ModelToken, Model); VirtualPathData vpd = RouteTable.Routes.GetVirtualPath(requestContext, routeValues); if (vpd != null) { path = vpd.VirtualPath; } } // If the virtual path is null, then there is no page to link to return path ?? String.Empty; } /// /// Looks up a column by the given name. If no column is found, an exception is thrown. /// /// /// public MetaColumn GetColumn(string columnName) { MetaColumn column; if (!TryGetColumn(columnName, out column)) { throw new InvalidOperationException(String.Format( CultureInfo.CurrentCulture, DynamicDataResources.MetaTable_NoSuchColumn, Name, columnName)); } return column; } private static int GetColumnOrder(MetaColumn column) { var displayAttribute = column.Metadata.DisplayAttribute; if (displayAttribute != null && displayAttribute.GetOrder() != null) { return displayAttribute.GetOrder().Value; } return DefaultColumnOrder; } private static int GetColumnOrder(MetaColumn column, IDictionary groupings) { var displayAttribute = column.Metadata.DisplayAttribute; int order; if (displayAttribute != null) { string groupName = displayAttribute.GetGroupName(); if (!String.IsNullOrEmpty(groupName) && groupings.TryGetValue(groupName, out order)) { return order; } } return GetColumnOrder(column); } /// /// Look for this table's primary key in the route values (i.e. typically the query string). /// If they're all found, return a DataKey containing the primary key values. Otherwise return null. /// public DataKey GetDataKeyFromRoute() { var queryStringKeys = new OrderedDictionary(PrimaryKeyNames.Length); foreach (MetaColumn key in PrimaryKeyColumns) { // Try to find the PK in the route values. If any PK is not found, return null string value = Misc.GetRouteValue(key.Name); if (string.IsNullOrEmpty(value)) return null; queryStringKeys[key.Name] = Misc.ChangeType(value, key.ColumnType); } return new DataKey(queryStringKeys, PrimaryKeyNames); } private MetaColumn GetDisplayColumnFromHeuristic() { // Pick best available option (except for columns based on custom properties) // 1. First non-PK string column // 2. First PK string column // 3. First PK non-string column // 4. First column (from all columns) var serverSideColumns = Columns.Where(c => !c.IsCustomProperty).ToList(); return serverSideColumns.FirstOrDefault(c => c.IsString && !c.IsPrimaryKey) ?? serverSideColumns.FirstOrDefault(c => c.IsString) ?? serverSideColumns.FirstOrDefault(c => c.IsPrimaryKey) ?? Columns.First(); } private MetaColumn GetDisplayColumnFromMetadata() { var displayColumnAttribute = Metadata.DisplayColumnAttribute; if (displayColumnAttribute == null) { return null; } MetaColumn displayColumn = null; if (!TryGetColumn(displayColumnAttribute.DisplayColumn, out displayColumn)) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DynamicDataResources.MetaTable_CantFindDisplayColumn, displayColumnAttribute.DisplayColumn, Name)); } return displayColumn; } /// /// Gets the value to be used as the display string for an instance of a row of this table when used in FK relationships. /// If the row is null, returns an empty string. If the entity class has an overidden ToString() method, returns the result /// of that method. Otherwise, returns the ToString representation of the value of the display column (as returned by the DisplayColumn /// property) for the given row. /// /// the instance of the row /// public virtual string GetDisplayString(object row) { if (row == null) return String.Empty; // Make sure it's of the right type, and handle collections row = PreprocessRowObject(row); // If there is a ToString() override, use it if (HasToStringOverride) { return row.ToString(); } // Otherwise, use the 'display column' object displayObject = DataBinder.GetPropertyValue(row, DisplayColumn.Name); return displayObject == null ? String.Empty : displayObject.ToString(); } /// /// Returns an enumeration of columns that are filterable by default. A column is filterable if it ///
    ///
  • is decorated with FilterAttribte with Enabled=true
  • ///
  • is scaffold, is not a custom property, and is either a FK column or a Bool column
  • ///
/// The enumeration is ordered by the value of the FilterAttribute.Order property. If a column /// does not have that attribute, the value 0 is used. ///
/// public virtual IEnumerable GetFilteredColumns() { IDictionary columnGroupOrder = GetColumnGroupingOrder(); return Columns.Where(c => IsFilterableColumn(c, Context.User)) .OrderBy(c => GetColumnOrder(c, columnGroupOrder)) .ThenBy(c => GetColumnOrder(c)); } private IDictionary GetColumnGroupingOrder() { // Group columns that have groups by group names. Then put them into a dictionary from group name -> // minimum column order so that groups are "stick" close together. return Columns.Where(c => c.Metadata.DisplayAttribute != null && !String.IsNullOrEmpty(c.Metadata.DisplayAttribute.GetGroupName())) .GroupBy(c => c.Metadata.DisplayAttribute.GetGroupName()) .ToDictionary(cg => cg.Key, cg => cg.Min(c => GetColumnOrder(c))); } /// /// Get a dictionary of primary key names and their values for the given row instance /// /// /// public IDictionary GetPrimaryKeyDictionary(object row) { row = PreprocessRowObject(row); Dictionary result = new Dictionary(); foreach (MetaColumn pkMember in PrimaryKeyColumns) { result.Add(pkMember.Name, DataBinder.GetPropertyValue(row, pkMember.Name)); } return result; } /// /// Get a comma separated list of values representing the primary key for the given row instance /// /// /// public string GetPrimaryKeyString(object row) { // Make sure it's of the right type, and handle collections row = PreprocessRowObject(row); return GetPrimaryKeyString(GetPrimaryKeyValues(row)); } /// /// Get a comma separated list of values representing the primary key /// /// /// public string GetPrimaryKeyString(IList primaryKeyValues) { return Misc.PersistListToCommaSeparatedString(primaryKeyValues); } /// /// Get the value of the primary key components for a given row /// /// /// public IList GetPrimaryKeyValues(object row) { if (row == null) return null; // Make sure it's of the right type, and handle collections row = PreprocessRowObject(row); return Misc.GetKeyValues(PrimaryKeyColumns, row); } /// /// Get the IQueryable for the entity type represented by this table (i.e. IQueryable of Product). Retrieves it from a new context /// instantiated using the CreateContext(). /// /// public IQueryable GetQuery() { return GetQuery(null); } /// /// Get the IQueryable for the entity type represented by this table (i.e. IQueryable of Product). Retrieves it from the provided /// context instance, or instantiates a new context using the CreateContext(). /// /// /// public virtual IQueryable GetQuery(object context) { if (context == null) { context = CreateContext(); } IQueryable query = Provider.GetQuery(context); if (EntityType != RootEntityType) { Expression ofTypeExpression = Expression.Call(typeof(Queryable), "OfType", new[] { EntityType }, query.Expression); query = query.Provider.CreateQuery(ofTypeExpression); } // Return the sorted query if there is a sort column if (SortColumn != null) { return Misc.BuildSortQueryable(query, this); } return query; } private void GetRouteValuesFromPK(RouteValueDictionary routeValues, IList primaryKeyValues) { if (primaryKeyValues != null) { for (int i = 0; i < PrimaryKeyNames.Length; i++) { routeValues.Add(PrimaryKeyNames[i], Misc.SanitizeQueryStringValue(primaryKeyValues[i])); } } } /// /// Returns an enumeration of columns that are to be displayed in a scaffolded context. By default all columns with the Scaffold /// property set to true are included, with the exception of: ///
    ///
  • Long-string columns (IsLongString property set to true) when the inListControl flag is true
  • ///
  • Children columns when mode is equal to Insert
  • ///
///
/// The mode, such as ReadOnly, Edit, or Insert. /// A flag indicating if the table is being displayed as an individual entity or as part of list-grid. /// public virtual IEnumerable GetScaffoldColumns(DataBoundControlMode mode, ContainerType containerType) { IDictionary columnGroupOrder = GetColumnGroupingOrder(); return Columns.Where(c => IsScaffoldColumn(c, mode, containerType)) .OrderBy(c => GetColumnOrder(c, columnGroupOrder)) .ThenBy(c => GetColumnOrder(c)); } /// /// Gets the table associated with the given type, regardless of which model it belongs to. /// public static MetaTable GetTable(Type entityType) { MetaTable table; if (!TryGetTable(entityType, out table)) { throw new InvalidOperationException(String.Format( CultureInfo.CurrentCulture, DynamicDataResources.MetaModel_EntityTypeDoesNotBelongToModel, entityType.FullName)); } return table; } /// /// Perform initialization logic for this table /// internal protected virtual void Initialize() { foreach (MetaColumn column in Columns) { column.Initialize(); } } internal static bool IsFilterableColumn(IMetaColumn column, IPrincipal user) { Debug.Assert(column != null); var displayAttribute = column.Attributes.FirstOrDefault(); if (displayAttribute != null && displayAttribute.GetAutoGenerateFilter().HasValue) { return displayAttribute.GetAutoGenerateFilter().Value; } if (!String.IsNullOrEmpty(column.FilterUIHint)) { return true; } // non-scaffolded columns should not be displayed by default if (!column.Scaffold) { return false; } // custom properties won't be queryable by the server if (column.IsCustomProperty) { return false; } var fkColumn = column as IMetaForeignKeyColumn; if (fkColumn != null) { // Only allow if the user has access to the parent table return fkColumn.ParentTable.CanRead(user); } if (column.ColumnType == typeof(bool)) { return true; } if (column.GetEnumType() != null) { return true; } return false; } private bool IsScaffoldColumn(IMetaColumn column, DataBoundControlMode mode, ContainerType containerType) { if (!column.Scaffold) { return false; } // Children columns don't make sense for new rows, so ignore them in Insert mode if ((mode == DataBoundControlMode.Insert) && (column is IMetaChildrenColumn)) { return false; } var fkColumn = column as IMetaForeignKeyColumn; if (fkColumn != null) { // Ignore the FK column if the user doesn't have access to the parent table if (!fkColumn.ParentTable.CanRead(Context.User)) { return false; } } return true; } public IDictionary GetColumnValuesFromRoute(HttpContext context) { return GetColumnValuesFromRoute(context.ToWrapper()); } internal IDictionary GetColumnValuesFromRoute(HttpContextBase context) { RouteValueDictionary routeValues = DynamicDataRouteHandler.GetRequestContext(context).RouteData.Values; Dictionary columnValues = new Dictionary(); foreach (var column in Columns) { if (Misc.IsColumnInDictionary(column, routeValues)) { MetaForeignKeyColumn foreignKeyColumn = column as MetaForeignKeyColumn; if (foreignKeyColumn != null) { // Add all the foreign keys to the column values. foreach (var fkName in foreignKeyColumn.ForeignKeyNames) { columnValues[fkName] = routeValues[fkName]; } } else { // Convert the value to the correct type. columnValues[column.Name] = Misc.ChangeType(routeValues[column.Name], column.ColumnType); } } } return columnValues; } private object PreprocessRowObject(object row) { // If null, nothing to do if (row == null) return null; // If it's of the correct entity type, we're done if (EntityType.IsAssignableFrom(row.GetType())) { return row; } // If it's a list, try using the first item var rowCollection = row as IList; if (rowCollection != null) { if (rowCollection.Count >= 1) { Debug.Assert(rowCollection.Count == 1); return PreprocessRowObject(rowCollection[0]); } } // We didn't recoginze the object, so return it unchanged return row; } /// /// Resets cached table metadata (i.e. information coming from attributes) as well as metadata of all columns. /// The metadata cache will be rebuilt the next time any metadata-derived information gets requested. /// public void ResetMetadata() { _metadata = null; _displayColumn = null; _sortColumnProcessed = false; foreach (var column in Columns) { column.ResetMetadata(); } } internal void SetScaffoldAndName(bool scaffoldDefaultValue, string nameOverride) { if (!String.IsNullOrEmpty(nameOverride)) { Name = nameOverride; } else if (Provider != null) { Name = Provider.Name; } _scaffoldDefaultValue = scaffoldDefaultValue; } /// /// /// /// [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] public override string ToString() { return Name; } /// /// Tries to find a column by the given name. If a column is found, it is assigned to the column /// variable and the method returns true. Otherwise, it returns false and column is null. /// /// /// /// public bool TryGetColumn(string columnName, out MetaColumn column) { if (columnName == null) { throw new ArgumentNullException("columnName"); } return _columnsByName.TryGetValue(columnName, out column); } /// /// Gets the table associated with the given type, regardless of which model it belongs to. /// public static bool TryGetTable(Type entityType, out MetaTable table) { MetaModel.CheckForRegistrationException(); if (entityType == null) { throw new ArgumentNullException("entityType"); } return System.Web.DynamicData.MetaModel.MetaModelManager.TryGetTable(entityType, out table); } #region IMetaTable Members string[] IMetaTable.PrimaryKeyNames { get { return PrimaryKeyNames; } } object IMetaTable.CreateContext() { return CreateContext(); } string IMetaTable.GetDisplayString(object row) { return GetDisplayString(row); } IQueryable IMetaTable.GetQuery(object context) { return GetQuery(context); } #endregion private class MetaTableMetadata { private DisplayNameAttribute _displayNameAttribute; private ReadOnlyAttribute _readOnlyAttribute; public MetaTableMetadata(MetaTable table) { Debug.Assert(table != null); Attributes = table.BuildAttributeCollection(); _readOnlyAttribute = Attributes.FirstOrDefault(); _displayNameAttribute = Attributes.FirstOrDefault(); DisplayColumnAttribute = Attributes.FirstOrDefault(); ScaffoldTable = Attributes.GetAttributePropertyValue(a => a.Scaffold, null); } public AttributeCollection Attributes { get; private set; } public DisplayColumnAttribute DisplayColumnAttribute { get; private set; } public string DisplayName { get { return _displayNameAttribute.GetPropertyValue(a => a.DisplayName, null); } } public bool? ScaffoldTable { get; private set; } public bool SortDescending { get { return DisplayColumnAttribute.GetPropertyValue(a => a.SortDescending, false); } } public bool IsReadOnly { get { return _readOnlyAttribute.GetPropertyValue(a => a.IsReadOnly, false); } } } ReadOnlyCollection IMetaTable.Columns { get { // Covariance only supported on interfaces return Columns.OfType().ToList().AsReadOnly(); } } IMetaModel IMetaTable.Model { get { return Model; } } IMetaColumn IMetaTable.DisplayColumn { get { return DisplayColumn; } } IMetaColumn IMetaTable.GetColumn(string columnName) { return GetColumn(columnName); } IEnumerable IMetaTable.GetFilteredColumns() { // We can remove the of type when we get rid of the Vnext solution since interface covariance support // was only added in 4.0 return GetFilteredColumns().OfType(); } IEnumerable IMetaTable.GetScaffoldColumns(DataBoundControlMode mode, ContainerType containerType) { // We can remove the of type when we get rid of the Vnext solution since interface covariance support // was only added in 4.0 return GetScaffoldColumns(mode, containerType).OfType(); } ReadOnlyCollection IMetaTable.PrimaryKeyColumns { get { return PrimaryKeyColumns.OfType().ToList().AsReadOnly(); } } IMetaColumn IMetaTable.SortColumn { get { return SortColumn; } } bool IMetaTable.TryGetColumn(string columnName, out IMetaColumn column) { MetaColumn metaColumn; column = null; if (TryGetColumn(columnName, out metaColumn)) { column = metaColumn; return true; } return false; } bool IMetaTable.CanDelete(IPrincipal principal) { return CanDelete(principal); } bool IMetaTable.CanInsert(IPrincipal principal) { return CanInsert(principal); } bool IMetaTable.CanRead(IPrincipal principal) { return CanRead(principal); } bool IMetaTable.CanUpdate(IPrincipal principal) { return CanUpdate(principal); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK