File: DynamicData\ModelProviders\EFColumnProvider.cs
Project: ndp\fx\src\xsp\system\DynamicData\System.Web.DynamicData.csproj (System.Web.DynamicData)
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Linq;
using System.Globalization;
using System.Reflection;
 
namespace System.Web.DynamicData.ModelProviders {
    internal sealed class EFColumnProvider : ColumnProvider {
        private EFTableProvider _table;
        private EFAssociationProvider _association;
        private bool _isAssociation;
        private bool _isSortableProcessed;
        private const string StoreGeneratedMetadata = "http://schemas.microsoft.com/ado/2009/02/edm/annotation:StoreGeneratedPattern";
 
        public EFColumnProvider(EntityType entityType, EFTableProvider table, EdmMember m, bool isPrimaryKey)
            : base(table) {
            EdmMember = m;
            IsPrimaryKey = isPrimaryKey;
            _table = table;
            MaxLength = 0;
            Name = EdmMember.Name;
            // 
            IsCustomProperty = false;
 
            // 
            var property = EdmMember as EdmProperty;
 
            if (property != null) {
                IsForeignKeyComponent = DetermineIsForeignKeyComponent(property);
                IsGenerated = IsServerGenerated(property);
            }
 
            ProcessFacets();
 
            var navProp = m as NavigationProperty;
            if (navProp != null) {
                _isAssociation = true;
                long key = EFAssociationProvider.BuildRelationshipKey(entityType, navProp.FromEndMember);
                ((EFDataModelProvider)table.DataModel).RelationshipEndLookup[key] = this;
            }
        }
 
        private bool DetermineIsForeignKeyComponent(EdmProperty property) {
            var navigationProperties = property.DeclaringType.Members.OfType<NavigationProperty>();
 
            // Look at all NavigationProperties (i.e. strongly-type relationship columns) of the table this column belong to and
            // see if there is a foreign key that matches this property
            // If this is a 1 to 0..1 relationship and we are processing the more primary side. i.e in the Student in Student-StudentDetail
            // and this is the primary key we don't want to check the relationship type since if there are no constraints we will treat the primary key as a foreign key.
            return navigationProperties.Any(n => EFAssociationProvider.GetDependentPropertyNames(n, !IsPrimaryKey /* checkRelationshipType */).Contains(property.Name));
        }
 
        private static bool IsServerGenerated(EdmProperty property) {
            MetadataProperty generated;
            if (property.MetadataProperties.TryGetValue(StoreGeneratedMetadata, false, out generated)) {
                return "Identity" == (string)generated.Value || "Computed" == (string)generated.Value;
            }
            return false;
        }
 
        private void ProcessFacets() {
            foreach (Facet facet in EdmMember.TypeUsage.Facets) {
                switch (facet.Name) {
                    case "MaxLength":
                        if (facet.IsUnbounded) {
                            // If it's marked as unbounded, treat it as max int
                            MaxLength = Int32.MaxValue;
                        }
                        else if (facet.Value != null && facet.Value is int) {
                            MaxLength = (int)facet.Value;
                        }
                        break;
                    case "Nullable":
                        Nullable = (bool)facet.Value;
                        break;
                }
            }
        }
 
        internal EdmMember EdmMember {
            get;
            private set;
        }
 
        #region IEntityMember Members
 
        public override PropertyInfo EntityTypeProperty {
            // 
            get { return _table.EntityType.GetProperty(Name); }
        }
 
        public override Type ColumnType {
            get {
                if (base.ColumnType == null) {
                    // 
 
 
                    var edmType = EdmMember.TypeUsage.EdmType;
                    if (edmType is EntityType) {
                        base.ColumnType = ((EFDataModelProvider)this.Table.DataModel).GetClrType(edmType);
                    }
                    else if (edmType is CollectionType) {
                        // get the EdmType that this CollectionType is wrapping
                        base.ColumnType = ((EFDataModelProvider)this.Table.DataModel).GetClrType(((CollectionType)edmType).TypeUsage.EdmType);
                    }
                    else if (edmType is PrimitiveType) {
                        base.ColumnType = ((PrimitiveType)edmType).ClrEquivalentType;
                    }
                    else if (edmType is EnumType) {
                        base.ColumnType = ((EFDataModelProvider)this.Table.DataModel).GetClrType((EnumType)edmType);
                    }
                    else {
                        Debug.Assert(false, String.Format(CultureInfo.CurrentCulture, "Unknown EdmType {0}.", edmType.GetType().FullName));
                    }
                }
                return base.ColumnType;
            }
        }
 
        public override bool IsSortable {
            get {
                if (!_isSortableProcessed) {
                    base.IsSortable = (ColumnType != typeof(byte[]));
                    _isSortableProcessed = true;
                }
                return base.IsSortable;
            }
        }
 
        public override AssociationProvider Association {
            get {
                if (!_isAssociation) {
                    return null;
                }
 
                if (_association == null) {
                    _association = new EFAssociationProvider(this, (NavigationProperty)EdmMember);
                }
                return _association;
            }
        }
 
        #endregion
 
        internal static bool IsSupportedEdmMemberType(EdmMember member) {
            var edmType = member.TypeUsage.EdmType;
            return edmType is EntityType || edmType is CollectionType || edmType is PrimitiveType || edmType is EnumType;
        }
    }
}