EntityDataSourceUtil.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 / DataWebControls / System / Data / WebControls / EntityDataSourceUtil.cs / 1305376 / EntityDataSourceUtil.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel; 
using System.Data.Metadata.Edm;
using System.Collections.ObjectModel; 
using System.Reflection; 
using System.Linq.Expressions;
using System.Reflection.Emit; 
using System.Data.EntityClient;
using System.Data.Objects;
using System.Collections;
using System.Data; 
using System.Data.Objects.DataClasses;
 
namespace System.Web.UI.WebControls 
{
    internal static class EntityDataSourceUtil 
    {
        #region Internal Util

        internal static readonly string EntitySqlElementAlias = "it"; 

        internal static T CheckArgumentNull(T value, string parameterName) where T : class 
        { 
            if (null == value)
            { 
                ThrowArgumentNullException(parameterName);
            }
            return value;
        } 

 
        ///  
        /// Indicates whether the given property name exists on the result.
        /// The result could be indicated by a wrapperCollection, an entitySet or a typeUsage, 
        /// any of which could be null.
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        internal static bool PropertyIsOnEntity(string propertyName, EntityDataSourceWrapperCollection wrapperCollection, EntitySet entitySet, TypeUsage tu)
        { 
            bool propertyIsOnEntity = false;
            if (null != wrapperCollection)
            {
                // check for descriptor 
                if (null != wrapperCollection.GetItemProperties(null).Find(propertyName, /*ignoreCase*/ false))
                { 
                    propertyIsOnEntity = true; 
                }
            } 
            if (null != tu)
            {
                ReadOnlyMetadataCollection members = null;
                switch (tu.EdmType.BuiltInTypeKind) 
                {
                    case BuiltInTypeKind.RowType: 
                        members = ((RowType)(tu.EdmType)).Members; 
                        break;
                    case BuiltInTypeKind.EntityType: 
                        members = ((EntityType)(tu.EdmType)).Members;
                        break;
                }
                if (null != members && members.Contains(propertyName)) 
                {
                    propertyIsOnEntity = true; 
                } 
            }
            if (null != entitySet) 
            {
                if ( ((EntityType)(entitySet.ElementType)).Members.Contains(propertyName) )
                {
                    propertyIsOnEntity = true; 
                }
            } 
            return propertyIsOnEntity; 
        }
 

        /// 
        /// Returns the value set onto the Parameter named by propertyName.
        /// If the Paramter does not have a value, it returns null. 
        /// 
        ///  
        ///  
        /// 
        ///  
        internal static object GetParameterValue(string propertyName, ParameterCollection parameterCollection,
                                                 EntityDataSource entityDataSource)
        {
            if (null == parameterCollection) // ParameterCollection undefined 
            {
                return null; 
            } 

            System.Collections.Specialized.IOrderedDictionary values = 
                parameterCollection.GetValues(entityDataSource.HttpContext, entityDataSource);

            foreach (object key in values.Keys)
            { 
                string parameterName = key as string;
                if (null != parameterName && String.Equals(propertyName, parameterName, StringComparison.Ordinal)) 
                { 
                    return values[parameterName];
                } 
            }

            return null;
        } 

 
        ///  
        /// Get the System.Web.UI.WebControls.Parameter that matches the name in the given ParameterCollection
        ///  
        /// 
        /// 
        /// 
        internal static Parameter GetParameter(string propertyName, ParameterCollection parameterCollection) 
        {
            if (null == parameterCollection) 
            { 
                return null;
            } 

            foreach (Parameter p in parameterCollection)
            {
                if (String.Equals(p.Name, propertyName, StringComparison.Ordinal)) 
                {
                    return p; 
                } 
            }
            return null; 
        }


        ///  
        /// Validates that the keys in the update parameters all match property names on the entityWrapper.
        ///  
        ///  
        /// 
        internal static void ValidateWebControlParameterNames(EntityDataSourceWrapper entityWrapper, 
                                                     ParameterCollection parameters,
                                                     EntityDataSource owner)
        {
            Debug.Assert(null != entityWrapper, "entityWrapper should not be null"); 
            if (null != parameters)
            { 
                PropertyDescriptorCollection entityProperties = entityWrapper.GetProperties(); 
                System.Collections.Specialized.IOrderedDictionary parmVals = parameters.GetValues(owner.HttpContext, owner);
                foreach (DictionaryEntry de in parmVals) 
                {
                    string key = de.Key as string;
                    if (null == key || null == entityProperties.Find(key, false))
                    { 
                        throw new InvalidOperationException(Strings.EntityDataSourceUtil_InsertUpdateParametersDontMatchPropertyNameOnEntity(key, entityWrapper.WrappedEntity.GetType().ToString()));
                    } 
                } 
            }
        } 


        /// 
        /// Verifies that the query's typeusage will not result in a polymorphic result. 
        /// If the query would be restricted "is of only" using entityTypeFilter, then
        /// this check assumes the result will not be polymorphic. 
        /// 
        /// This method is only called if the user specifies EntitySetName and updates are enabled.
        /// 
        /// Does nothing for RowTypes.
        /// 
        /// The TypeUsage from the query
        ///  
        /// 
        internal static void CheckNonPolymorphicTypeUsage(EntityType entityType, 
                                                          ItemCollection ocItemCollection, 
                                                          string entityTypeFilter)
        { 
            CheckArgumentNull(ocItemCollection, "ocItemCollection");

            if (String.IsNullOrEmpty(entityTypeFilter))
            { 
                List types = new List(EntityDataSourceUtil.GetTypeAndSubtypesOf(entityType, ocItemCollection, /*includeAbstractTypes*/true));
                if (entityType.BaseType != null || 
                    types.Count() > 1 || entityType.Abstract) 
                {
                    throw new InvalidOperationException(Strings.EntityDataSourceUtil_EntityQueryCannotReturnPolymorphicTypes); 
                }
            }

            return; 
        }
 
        internal static IEnumerable GetTypeAndSubtypesOf(EntityType type, ReadOnlyCollection itemCollection, bool includeAbstractTypes) 
        {
            if (includeAbstractTypes || !type.Abstract) 
            {
                yield return type;
            }
 
            // Get entity sub-types
            foreach (EdmType subType in GetTypeAndSubtypesOf(type, itemCollection, includeAbstractTypes)) 
            { 
                yield return subType;
            } 

            // Get complex sub-types
            foreach (EdmType subType in GetTypeAndSubtypesOf(type, itemCollection, includeAbstractTypes))
            { 
                yield return subType;
            } 
        } 

        internal static bool IsTypeOrSubtypeOf(EntityType superType, EntityType derivedType, ReadOnlyCollection itemCollection) 
        {
            IEnumerable types = GetTypeAndSubtypesOf(superType, itemCollection, false);
            foreach(EdmType type in types)
            { 
                if (type == derivedType)
                { 
                    return true; 
                }
            } 
            return false;
        }

        internal static Type GetClrType(MetadataWorkspace ocWorkspace, StructuralType edmType) 
        {
            StructuralType oSpaceType = (StructuralType)ocWorkspace.GetObjectSpaceType(edmType); 
            ObjectItemCollection objectItemCollection = 
                (ObjectItemCollection)(ocWorkspace.GetItemCollection(DataSpace.OSpace));
            return objectItemCollection.GetClrType(oSpaceType); 
        }

        internal static ConstructorInfo GetConstructorInfo(Type type)
        { 
            Debug.Assert(null != type, "type required");
            ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, System.Type.EmptyTypes, null); 
 
            if (null == constructorInfo)
            { 
                throw new InvalidOperationException(Strings.DefaultConstructorNotFound(type));
            }

            return constructorInfo; 
        }
 
        internal static PropertyInfo GetPropertyInfo(Type type, string name) 
        {
            Debug.Assert(null != type, "type required"); 
            Debug.Assert(null != name, "name required");

            PropertyInfo propertyInfo = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, null, Type.EmptyTypes, null);
 
            if (null == propertyInfo)
            { 
                throw new InvalidOperationException(Strings.PropertyNotFound(name, type)); 
            }
 
            return propertyInfo;
        }

        internal static object InitializeType(Type type) 
        {
            ConstructorInfo constructorInfo = GetConstructorInfo(type); 
            return constructorInfo.Invoke(new object[] { }); 
        }
 
        /// 
        /// Given a data source column name, returns the corresponding Entity-SQL. If
        /// we are using the wrapper, we defer to the property descriptor to get
        /// the string. If there is no wrapper (or no corresponding property descriptor) 
        /// we use the column name directly.
        ///  
        /// Column name for which we produce a value expression. 
        /// Entity-SQL for column.
        internal static string GetEntitySqlValueForColumnName(string columnName, EntityDataSourceWrapperCollection wrapperCollection) 
        {
            Debug.Assert(!String.IsNullOrEmpty(columnName), "columnName must be given");

            string result = null; 

            if (wrapperCollection != null) 
            { 
                // use wrapper definition if it is available
                EntityDataSourceWrapperPropertyDescriptor descriptor = 
                    wrapperCollection.GetItemProperties(null).Find(columnName, false) as EntityDataSourceWrapperPropertyDescriptor;
                if (null != descriptor)
                {
                    result = descriptor.Column.GetEntitySqlValue(); 
                }
            } 
 
            // if descriptor does not provide SQL, create the default: it._columnName_
            if (null == result) 
            {
                result = EntitySqlElementAlias + "." + QuoteEntitySqlIdentifier(columnName);
            }
 
            return result;
        } 
 
        internal static Type ConvertTypeCodeToType(TypeCode typeCode)
        { 
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return typeof(Boolean); 

                case TypeCode.Byte: 
                    return typeof(Byte); 

                case TypeCode.Char: 
                    return typeof(Char);

                case TypeCode.DateTime:
                    return typeof(DateTime); 

                case TypeCode.DBNull: 
                    return typeof(DBNull); 

                case TypeCode.Decimal: 
                    return typeof(Decimal);

                case TypeCode.Double:
                    return typeof(Double); 

                case TypeCode.Empty: 
                    return null; 

                case TypeCode.Int16: 
                    return typeof(Int16);

                case TypeCode.Int32:
                    return typeof(Int32); 

                case TypeCode.Int64: 
                    return typeof(Int64); 

                case TypeCode.Object: 
                    return typeof(Object);

                case TypeCode.SByte:
                    return typeof(SByte); 

                case TypeCode.Single: 
                    return typeof(Single); 

                case TypeCode.String: 
                    return typeof(String);

                case TypeCode.UInt16:
                    return typeof(UInt16); 

                case TypeCode.UInt32: 
                    return typeof(UInt32); 

                case TypeCode.UInt64: 
                    return typeof(UInt64);

                default:
                    throw new InvalidOperationException(Strings.EntityDataSourceUtil_UnableToConvertTypeCodeToType(typeCode.ToString())); 
            }
        } 
 
        /// 
        /// Converts a DB type code to a CLR type, bypassing CLR type codes since there 
        /// is not a sufficient mapping.
        /// 
        /// The DB type to convert
        /// The mapped CLR type 
        internal static Type ConvertDbTypeToType(DbType dbType)
        { 
            switch (dbType) 
            {
                case DbType.AnsiString: 
                case DbType.AnsiStringFixedLength:
                case DbType.String:
                case DbType.StringFixedLength:
                    return typeof(String); 
                case DbType.Boolean:
                    return typeof(Boolean); 
                case DbType.Byte: 
                    return typeof(Byte);
                case DbType.VarNumeric:     // 
                case DbType.Currency:
                case DbType.Decimal:
                    return typeof(Decimal);
                case DbType.Date: 
                case DbType.DateTime:
                case DbType.DateTime2: // new Katmai type 
                    return typeof(DateTime); 
                case DbType.Time:      // new Katmai type
                    return typeof(TimeSpan); 
                case DbType.Double:
                    return typeof(Double);
                case DbType.Int16:
                    return typeof(Int16); 
                case DbType.Int32:
                    return typeof(Int32); 
                case DbType.Int64: 
                    return typeof(Int64);
                case DbType.SByte: 
                    return typeof(SByte);
                case DbType.Single:
                    return typeof(Single);
                case DbType.UInt16: 
                    return typeof(UInt16);
                case DbType.UInt32: 
                    return typeof(UInt32); 
                case DbType.UInt64:
                    return typeof(UInt64); 
                case DbType.Guid:
                    return typeof(Guid);
                case DbType.DateTimeOffset: // new Katmai type
                    return typeof(DateTimeOffset); 
                case DbType.Binary:
                    return typeof(byte[]); 
                case DbType.Object: 
                default:
                    return typeof(Object); 
            }
        }

        #endregion 

        #region Private helper method 
 
        private static IEnumerable GetTypeAndSubtypesOf(EdmType type, ReadOnlyCollection itemCollection, bool includeAbstractTypes)
            where T_EdmType : EdmType 
        {
            // Get the subtypes of the type from the WorkSpace
            T_EdmType specificType = type as T_EdmType;
            if (specificType != null) 
            {
 
                IEnumerable typesInWorkSpace = itemCollection.OfType(); 
                foreach (T_EdmType typeInWorkSpace in typesInWorkSpace)
                { 
                    if (specificType.Equals(typeInWorkSpace) == false && IsStrictSubtypeOf(typeInWorkSpace, specificType))
                    {
                        if (includeAbstractTypes || !typeInWorkSpace.Abstract)
                        { 
                            yield return typeInWorkSpace;
                        } 
 
                    }
                } 
            }
            yield break;
        }
 
        // requires: firstType is not null
        // effects: if otherType is among the base types, return true, 
        // otherwise returns false. 
        // when othertype is same as the current type, return false.
        private static bool IsStrictSubtypeOf(EdmType firstType, EdmType secondType) 
        {
            Debug.Assert(firstType != null, "firstType should not be not null");
            if (secondType == null)
            { 
                return false;
            } 
 
            // walk up my type hierarchy list
            for (EdmType t = firstType.BaseType; t != null; t = t.BaseType) 
            {
                if (t == secondType)
                    return true;
            } 
            return false;
        } 
 
        internal static bool NullCanBeAssignedTo(Type type)
        { 
            Debug.Assert(null != type, "type required");
            return !type.IsValueType || IsNullableType(type, out type);
        }
 
        internal static bool IsNullableType(Type type, out Type underlyingType)
        { 
            Debug.Assert(null != type, "type required"); 
            if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            { 
                underlyingType = type.GetGenericArguments()[0];
                return true;
            }
            underlyingType = null; 
            return false;
        } 
 
        internal static void ThrowArgumentNullException(string parameterName)
        { 
            throw ArgumentNull(parameterName);
        }

        internal static ArgumentNullException ArgumentNull(string parameter) 
        {
            ArgumentNullException e = new ArgumentNullException(parameter); 
            return e; 
        }
 
        internal static object ConvertType(object value, Type type, string paramName)
        {
            // NOTE: This method came from ObjectDataSource via LinqDataSource.
            // It has been changed to support better parsing of decimal values. 
            string s = value as string;
            if (s != null) 
            { 
                // Get the type converter for the destination type
                TypeConverter converter = TypeDescriptor.GetConverter(type); 
                if (converter != null)
                {
                    // Perform the conversion
                    try 
                    {
                        // If requested type is a decimal, then first try to parse using the Decimal parsing 
                        // which is able to handle comma thousands separators.  If this doesn't work, or 
                        // requested value is not a decimal, then fall back on the type converter mechanism.
                        decimal decimalResult; 
                        if (type.IsAssignableFrom(typeof(Decimal)) && Decimal.TryParse(s, out decimalResult))
                        {
                            value = decimalResult;
                        } 
                        else
                        { 
                            value = converter.ConvertFromString(s); 
                        }
                    } 
                    catch (Exception) // ConvertFromString sometimes throws exceptions of actual type Exception!
                    {
                        // For Nullable types, we just get the type parameter since that makes a more readable exception message
                        string typeName; 
                        if (type.IsGenericType && typeof(Nullable<>).IsAssignableFrom(type.GetGenericTypeDefinition()) && !type.ContainsGenericParameters)
                        { 
                            Type[] types = type.GetGenericArguments(); 
                            Debug.Assert(types != null && types.Length == 1, "Nullable did not have a single generic type.");
                            typeName = types[0].FullName; 
                        }
                        else
                        {
                            typeName = type.FullName; 
                        }
                        throw new InvalidOperationException(Strings.EntityDataSourceUtil_UnableToConvertStringToType(paramName, typeName)); 
                    } 
                }
            } 
            return value;
        }

        internal static void SetAllPropertiesWithVerification(EntityDataSourceWrapper entityWrapper, 
                                                              Dictionary changedProperties,
                                                              bool overwrite) 
        { 
            Dictionary exceptions = null;
            entityWrapper.SetAllProperties(changedProperties, /*overwriteSameValue*/true, ref exceptions); 

            if (null != exceptions)
            {
                // The EntityDataSourceValidationException has a property "InnerExceptions" that encapsulates 
                // all of the failed property setters. The message from one of those errors is surfaced so that it
                // appears on the web page as a human-readable error like: 
                //   "Error while setting property 'PropertyName': 'The value cannot be null.'." 
                string key = exceptions.Keys.First();
                throw new EntityDataSourceValidationException( 
                    Strings.EntityDataSourceView_DataConversionError(
                        key, exceptions[key].Message), exceptions);
            }
        } 

        ///  
        /// Get the Clr type for the primitive or complex type member. The member must not be null. 
        /// 
        internal static Type GetMemberClrType(MetadataWorkspace ocWorkspace, EdmMember member) 
        {
            EntityDataSourceUtil.CheckArgumentNull(member, "member");

            EdmType memberType = member.TypeUsage.EdmType; 

            Debug.Assert(memberType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType || 
                memberType.BuiltInTypeKind == BuiltInTypeKind.ComplexType || 
                memberType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "member type must be primitive, entity or complex type");
 
            Type clrType;

            if (memberType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
            { 
                PrimitiveType primitiveType = (PrimitiveType)memberType;
 
                clrType = primitiveType.ClrEquivalentType; 

                if (!NullCanBeAssignedTo(clrType)) 
                {
                    Facet facet;
                    if (member.TypeUsage.Facets.TryGetValue("Nullable", true, out facet))
                    { 
                        if ((bool)facet.Value)
                        { 
                            clrType = MakeNullable(clrType); 
                        }
                    } 
                }
            }
            else if (memberType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
            { 
                EntityType entityType = (EntityType)memberType;
 
                clrType = GetClrType(ocWorkspace, entityType); 
            }
            else 
            {
                ComplexType complexType = (ComplexType)memberType;

                clrType = GetClrType(ocWorkspace, complexType); 
            }
 
            return clrType; 
        }
 
        /// Get the Clr type for the primitive type member. The member must not be null.
        internal static Type GetPrimitiveMemberClrType(EdmMember member)
        {
            Debug.Assert(member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "member must be primitive member"); 

            MetadataWorkspace ocWorkspace = null; // workspace is not required to determine CLR primitive type 
 
            return GetMemberClrType(ocWorkspace, member);
        } 

        internal static Type MakeNullable(Type type)
        {
            if (!NullCanBeAssignedTo(type)) 
            {
                type = typeof(Nullable<>).MakeGenericType(type); 
            } 
            return type;
        } 

        /// 
        /// Returns the collection of AssociationSetEnds for the relationships for this entity
        ///  
        /// 
        ///  
        /// If true, returns only the other ends with multiplicity 1. Ignores 1:0..1 relationships. 
        /// 
        internal static IEnumerable GetReferenceEnds(EntitySet entitySet, EntityType entityType, bool forKey) 
        {
            foreach (AssociationSet associationSet in entitySet.EntityContainer.BaseEntitySets.OfType())
            {
                Debug.Assert(associationSet.AssociationSetEnds.Count == 2, "non binary association?"); 
                AssociationSetEnd firstEnd = associationSet.AssociationSetEnds[0];
                AssociationSetEnd secondEnd = associationSet.AssociationSetEnds[1]; 
 
                // If both ends match, then we will return both ends
                if (IsReferenceEnd(entitySet, entityType, firstEnd, secondEnd, forKey)) 
                {
                    yield return secondEnd;
                }
                if (IsReferenceEnd(entitySet, entityType, secondEnd, firstEnd, forKey)) 
                {
                    yield return firstEnd; 
                } 
            }
        } 

        /// 
        /// Determine if the end is 'contained' in the source entity via a referential integrity constraint (e.g.,
        /// in a relationship from OrderDetail to Order where OrderDetail has the OrderId property, the association set end 
        /// is contained in the order detail entity)
        ///  
        private static bool IsContained(AssociationSetEnd end, out ReferentialConstraint constraint) 
        {
            CheckArgumentNull(end, "end"); 

            AssociationEndMember endMember = end.CorrespondingAssociationEndMember;
            AssociationType associationType = (AssociationType)endMember.DeclaringType;
 
            constraint = null;
            bool result = false; 
 
            if (null != associationType.ReferentialConstraints)
            { 
                foreach (ReferentialConstraint candidate in associationType.ReferentialConstraints)
                {
                    if (candidate.FromRole.Name == endMember.Name)
                    { 
                        constraint = candidate;
                        result = true; 
                        break; 
                    }
                } 
            }

            return result;
        } 

        internal static bool TryGetCorrespondingNavigationProperty(AssociationEndMember end, out NavigationProperty navigationProperty) 
        { 
            EntityType entityType = GetEntityType(GetOppositeEnd(end));
 
            // if there is a corresponding navigation property, use its name as the prefix
            navigationProperty = entityType.NavigationProperties
                .Where(np => np.ToEndMember == end)
                .SingleOrDefault(); // metadata is supposed to ensure this is non-ambiguous 
            return null != navigationProperty;
        } 
 
        internal static AssociationEndMember GetOppositeEnd(AssociationEndMember end)
        { 
            return (AssociationEndMember)end.DeclaringType.Members.Where(m => m != end).Single();
        }

        ///  
        /// A navigation ('fromEnd' -> 'toEnd') defines a reference end for 'entitySet' and 'entityType' if it
        /// has multiplicity 0..1 or 1..1, is bound to the set, and has the appropriate type. 
        /// 
        /// We omit 1..1:0..1 navigations assuming that the opposite end owns the relationship (since the foreign
        /// key would need to point in the opposite direction.) 
        /// 
        private static bool IsReferenceEnd(EntitySet entitySet, EntityType entityType, AssociationSetEnd fromEnd, AssociationSetEnd toEnd, bool forKey)
        {
            EntityType fromType = GetEntityType(fromEnd); 

            if (fromEnd.EntitySet == entitySet && (IsStrictSubtypeOf(entityType, fromType) || entityType == fromType)) 
            { 
                RelationshipMultiplicity fromMult = fromEnd.CorrespondingAssociationEndMember.RelationshipMultiplicity;
                RelationshipMultiplicity toMult = toEnd.CorrespondingAssociationEndMember.RelationshipMultiplicity; 

                // If forKey is false (we are testing to see if this is a far end for a reference, not a key)
                //   then fromMult is ignored and all far-end 1 or 0..1 multiplicity ends are exposed.
                // If forKey is true, then we are asking about a reference end for the purpose of flattening. 
                //   We do not flatten 1:0..1 relationships because of a limitation in the EDM.
                if (toMult == RelationshipMultiplicity.One || 
                    (toMult == RelationshipMultiplicity.ZeroOrOne && (!forKey || fromMult != RelationshipMultiplicity.One) )) 
                {
                    return true; 
                }
            }

            return false; 
        }
 
        internal static EntityType GetEntityType(AssociationSetEnd end) 
        {
            return GetEntityType(end.CorrespondingAssociationEndMember); 
        }

        internal static EntityType GetEntityType(AssociationEndMember end)
        { 
            EntityType entityType = (EntityType)((RefType)end.TypeUsage.EdmType).ElementType;
            return entityType; 
        } 

        internal static string GetQualifiedEntitySetName(EntitySet entitySet) 
        {
            EntityDataSourceUtil.CheckArgumentNull(entitySet, "entitySet");
            // ContainerName.EntitySetName
            return entitySet.EntityContainer.Name + "." + entitySet.Name; 
        }
 
        internal static string QuoteEntitySqlIdentifier(string identifier) 
        {
            return "[" + (identifier ?? string.Empty).Replace("]", "]]") + "]"; 
        }

        internal static string CreateEntitySqlTypeIdentifier(EdmType type)
        { 
            // [_schema_namespace_name_].[_type_name_]
            return QuoteEntitySqlIdentifier(type.NamespaceName) + "." + QuoteEntitySqlIdentifier(type.Name); 
        } 

        internal static string CreateEntitySqlSetIdentifier(EntitySetBase set) 
        {
            // [_container_name_].[_set_name_]
            return QuoteEntitySqlIdentifier(set.EntityContainer.Name) + "." + QuoteEntitySqlIdentifier(set.Name);
        } 

        ///  
        /// Determines which columns to expose for the given set and type. Includes 
        /// flattened complex properties and 'reference' keys.
        ///  
        /// Used to determine 'interesting' members, or
        /// members whose values need to be maintained in ControlState
        /// Used to get CLR mapping information for EDM
        /// types 
        /// The set.
        /// The type. 
        /// A map from display names to columns. 
        internal static ReadOnlyCollection GetNamedColumns(MetadataWorkspace csWorkspace, MetadataWorkspace ocWorkspace,
            EntitySet entitySet, EntityType entityType) 
        {
            CheckArgumentNull(csWorkspace, "csWorkspace");
            CheckArgumentNull(ocWorkspace, "ocWorkspace");
            CheckArgumentNull(entitySet, "entitySet"); 
            CheckArgumentNull(entityType, "entityType");
 
            ReadOnlyCollection interestingMembers = GetInterestingMembers(csWorkspace, entitySet, entityType); 

            IEnumerable columns = GetColumns(entitySet, entityType, ocWorkspace, interestingMembers); 
            List result = new List();

            // give precedence to simple named columns (
 
            HashSet usedNames = new HashSet();
            foreach (EntityDataSourceColumn column in columns) 
            { 
                if (!column.IsHidden)
                { 
                    // check that the column name has not been used
                    if (!usedNames.Add(column.DisplayName))
                    {
                        throw new InvalidOperationException(Strings.DisplayNameCollision(column.DisplayName)); 
                    }
                } 
                result.Add(column); 
            }
 
            return result.AsReadOnly();
        }

        private static ReadOnlyCollection GetInterestingMembers(MetadataWorkspace csWorkspace, EntitySet entitySet, EntityType entityType) 
        {
            // Note that this delegate is not used to determine whether reference columns are interesting. They 
            // are intrinsically interesting and do not appear in this set. 
            HashSet interestingMembers = new HashSet(
                csWorkspace.GetRequiredOriginalValueMembers(entitySet, entitySet.ElementType)); 

            // keys are also interesting...
            foreach (EdmMember keyMember in entityType.KeyMembers)
            { 
                interestingMembers.Add(keyMember);
            } 
 
            // complex properties are also interesting
            foreach (EdmMember member in entityType.Members) 
            {
                if (member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                {
                    interestingMembers.Add(member); 
                }
            } 
 

            ReadOnlyCollection result = interestingMembers.ToList().AsReadOnly(); 

            return result;
        }
 
        private static IEnumerable GetColumns(EntitySet entitySet, EntityType entityType,
            MetadataWorkspace ocWorkspace, ReadOnlyCollection interestingMembers) 
        { 
            List columns = new List();
 
            // Primitive and complex properties
            EntityDataSourceMemberPath parent = null; // top-level properties are not qualified
            Dictionary entityProperties = AddPropertyColumns(columns, ocWorkspace, parent, entityType.Properties, interestingMembers);
 
            // Navigation reference properties
            AddReferenceNavigationColumns(columns, ocWorkspace, entitySet, entityType); 
 
            // Reference key properties
            AddReferenceKeyColumns(columns, ocWorkspace, entitySet, entityType, entityProperties); 

            return columns;
        }
 
        // Adds element to 'columns' for every element of 'properties'. Also returns a map from properties
        // at this level to the corresponding columns. 
        private static Dictionary AddPropertyColumns(List columns, MetadataWorkspace ocWorkspace, EntityDataSourceMemberPath parent, IEnumerable properties, ReadOnlyCollection interestingMembers) 
        {
            Dictionary result = new Dictionary(); 

            foreach (EdmProperty property in properties)
            {
                bool isLocallyInteresting = interestingMembers.Contains(property); 

                EntityDataSourceMemberPath prefix = new EntityDataSourceMemberPath(ocWorkspace, parent, property, isLocallyInteresting); 
                EdmType propertyType = property.TypeUsage.EdmType; 

                // add column for this entity property 
                EntityDataSourcePropertyColumn propertyColumn = new EntityDataSourcePropertyColumn(prefix);
                columns.Add(propertyColumn);
                result.Add(property, propertyColumn);
 
                if (propertyType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                { 
                    // add nested properties 
                    // prepend the property name to the members of the complex type
                    AddPropertyColumns(columns, ocWorkspace, prefix, ((ComplexType)propertyType).Properties, interestingMembers); 
                }
                // other property types are not currently supported (or possible in EF V1 for that matter)
            }
 
            return result;
        } 
 
        private static void AddReferenceNavigationColumns(List columns, MetadataWorkspace ocWorkspace, EntitySet entitySet, EntityType entityType)
        { 
            foreach (AssociationSetEnd toEnd in GetReferenceEnds(entitySet, entityType, /*forKey*/false))
            {
                // Check for a navigation property
                NavigationProperty navigationProperty; 
                if (TryGetCorrespondingNavigationProperty(toEnd.CorrespondingAssociationEndMember, out navigationProperty))
                { 
                    Type clrToType = EntityDataSourceUtil.GetMemberClrType(ocWorkspace, navigationProperty); 
                    EntityDataSourceReferenceValueColumn column = EntityDataSourceReferenceValueColumn.Create(clrToType, ocWorkspace, navigationProperty);
                    columns.Add(column); 
                }
            }
        }
 
        private static void AddReferenceKeyColumns(List columns, MetadataWorkspace ocWorkspace, EntitySet entitySet, EntityType entityType, Dictionary entityProperties)
        { 
            foreach (AssociationSetEnd toEnd in GetReferenceEnds(entitySet, entityType, /*forKey*/true)) 
            {
                ReferentialConstraint constraint; 
                bool isContained = EntityDataSourceUtil.IsContained(toEnd, out constraint);

                    // Create a group for the end columns
                    EntityType toType = EntityDataSourceUtil.GetEntityType(toEnd); 
                    Type clrToType = EntityDataSourceUtil.GetClrType(ocWorkspace, toType);
 
                    EntityDataSourceReferenceGroup group = EntityDataSourceReferenceGroup.Create(clrToType, toEnd); 

                    // Create a column for every key 
                    foreach (EdmProperty keyMember in GetEntityType(toEnd).KeyMembers)
                    {
                        EntityDataSourceColumn controllingColumn = null;
                        if (isContained) 
                        {
                            // if this key is 'contained' in the entity, make the referential constrained 
                            // property the principal for the column 
                            int ordinalInConstraint = constraint.FromProperties.IndexOf(keyMember);
 
                            // find corresponding member in the current (dependent) entity
                            EdmProperty correspondingProperty = constraint.ToProperties[ordinalInConstraint];

                            controllingColumn = entityProperties[correspondingProperty]; 
                        }
                        columns.Add(new EntityDataSourceReferenceKeyColumn(group, keyMember, controllingColumn)); 
                    } 
            }
        } 

        #endregion

    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel; 
using System.Data.Metadata.Edm;
using System.Collections.ObjectModel; 
using System.Reflection; 
using System.Linq.Expressions;
using System.Reflection.Emit; 
using System.Data.EntityClient;
using System.Data.Objects;
using System.Collections;
using System.Data; 
using System.Data.Objects.DataClasses;
 
namespace System.Web.UI.WebControls 
{
    internal static class EntityDataSourceUtil 
    {
        #region Internal Util

        internal static readonly string EntitySqlElementAlias = "it"; 

        internal static T CheckArgumentNull(T value, string parameterName) where T : class 
        { 
            if (null == value)
            { 
                ThrowArgumentNullException(parameterName);
            }
            return value;
        } 

 
        ///  
        /// Indicates whether the given property name exists on the result.
        /// The result could be indicated by a wrapperCollection, an entitySet or a typeUsage, 
        /// any of which could be null.
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        internal static bool PropertyIsOnEntity(string propertyName, EntityDataSourceWrapperCollection wrapperCollection, EntitySet entitySet, TypeUsage tu)
        { 
            bool propertyIsOnEntity = false;
            if (null != wrapperCollection)
            {
                // check for descriptor 
                if (null != wrapperCollection.GetItemProperties(null).Find(propertyName, /*ignoreCase*/ false))
                { 
                    propertyIsOnEntity = true; 
                }
            } 
            if (null != tu)
            {
                ReadOnlyMetadataCollection members = null;
                switch (tu.EdmType.BuiltInTypeKind) 
                {
                    case BuiltInTypeKind.RowType: 
                        members = ((RowType)(tu.EdmType)).Members; 
                        break;
                    case BuiltInTypeKind.EntityType: 
                        members = ((EntityType)(tu.EdmType)).Members;
                        break;
                }
                if (null != members && members.Contains(propertyName)) 
                {
                    propertyIsOnEntity = true; 
                } 
            }
            if (null != entitySet) 
            {
                if ( ((EntityType)(entitySet.ElementType)).Members.Contains(propertyName) )
                {
                    propertyIsOnEntity = true; 
                }
            } 
            return propertyIsOnEntity; 
        }
 

        /// 
        /// Returns the value set onto the Parameter named by propertyName.
        /// If the Paramter does not have a value, it returns null. 
        /// 
        ///  
        ///  
        /// 
        ///  
        internal static object GetParameterValue(string propertyName, ParameterCollection parameterCollection,
                                                 EntityDataSource entityDataSource)
        {
            if (null == parameterCollection) // ParameterCollection undefined 
            {
                return null; 
            } 

            System.Collections.Specialized.IOrderedDictionary values = 
                parameterCollection.GetValues(entityDataSource.HttpContext, entityDataSource);

            foreach (object key in values.Keys)
            { 
                string parameterName = key as string;
                if (null != parameterName && String.Equals(propertyName, parameterName, StringComparison.Ordinal)) 
                { 
                    return values[parameterName];
                } 
            }

            return null;
        } 

 
        ///  
        /// Get the System.Web.UI.WebControls.Parameter that matches the name in the given ParameterCollection
        ///  
        /// 
        /// 
        /// 
        internal static Parameter GetParameter(string propertyName, ParameterCollection parameterCollection) 
        {
            if (null == parameterCollection) 
            { 
                return null;
            } 

            foreach (Parameter p in parameterCollection)
            {
                if (String.Equals(p.Name, propertyName, StringComparison.Ordinal)) 
                {
                    return p; 
                } 
            }
            return null; 
        }


        ///  
        /// Validates that the keys in the update parameters all match property names on the entityWrapper.
        ///  
        ///  
        /// 
        internal static void ValidateWebControlParameterNames(EntityDataSourceWrapper entityWrapper, 
                                                     ParameterCollection parameters,
                                                     EntityDataSource owner)
        {
            Debug.Assert(null != entityWrapper, "entityWrapper should not be null"); 
            if (null != parameters)
            { 
                PropertyDescriptorCollection entityProperties = entityWrapper.GetProperties(); 
                System.Collections.Specialized.IOrderedDictionary parmVals = parameters.GetValues(owner.HttpContext, owner);
                foreach (DictionaryEntry de in parmVals) 
                {
                    string key = de.Key as string;
                    if (null == key || null == entityProperties.Find(key, false))
                    { 
                        throw new InvalidOperationException(Strings.EntityDataSourceUtil_InsertUpdateParametersDontMatchPropertyNameOnEntity(key, entityWrapper.WrappedEntity.GetType().ToString()));
                    } 
                } 
            }
        } 


        /// 
        /// Verifies that the query's typeusage will not result in a polymorphic result. 
        /// If the query would be restricted "is of only" using entityTypeFilter, then
        /// this check assumes the result will not be polymorphic. 
        /// 
        /// This method is only called if the user specifies EntitySetName and updates are enabled.
        /// 
        /// Does nothing for RowTypes.
        /// 
        /// The TypeUsage from the query
        ///  
        /// 
        internal static void CheckNonPolymorphicTypeUsage(EntityType entityType, 
                                                          ItemCollection ocItemCollection, 
                                                          string entityTypeFilter)
        { 
            CheckArgumentNull(ocItemCollection, "ocItemCollection");

            if (String.IsNullOrEmpty(entityTypeFilter))
            { 
                List types = new List(EntityDataSourceUtil.GetTypeAndSubtypesOf(entityType, ocItemCollection, /*includeAbstractTypes*/true));
                if (entityType.BaseType != null || 
                    types.Count() > 1 || entityType.Abstract) 
                {
                    throw new InvalidOperationException(Strings.EntityDataSourceUtil_EntityQueryCannotReturnPolymorphicTypes); 
                }
            }

            return; 
        }
 
        internal static IEnumerable GetTypeAndSubtypesOf(EntityType type, ReadOnlyCollection itemCollection, bool includeAbstractTypes) 
        {
            if (includeAbstractTypes || !type.Abstract) 
            {
                yield return type;
            }
 
            // Get entity sub-types
            foreach (EdmType subType in GetTypeAndSubtypesOf(type, itemCollection, includeAbstractTypes)) 
            { 
                yield return subType;
            } 

            // Get complex sub-types
            foreach (EdmType subType in GetTypeAndSubtypesOf(type, itemCollection, includeAbstractTypes))
            { 
                yield return subType;
            } 
        } 

        internal static bool IsTypeOrSubtypeOf(EntityType superType, EntityType derivedType, ReadOnlyCollection itemCollection) 
        {
            IEnumerable types = GetTypeAndSubtypesOf(superType, itemCollection, false);
            foreach(EdmType type in types)
            { 
                if (type == derivedType)
                { 
                    return true; 
                }
            } 
            return false;
        }

        internal static Type GetClrType(MetadataWorkspace ocWorkspace, StructuralType edmType) 
        {
            StructuralType oSpaceType = (StructuralType)ocWorkspace.GetObjectSpaceType(edmType); 
            ObjectItemCollection objectItemCollection = 
                (ObjectItemCollection)(ocWorkspace.GetItemCollection(DataSpace.OSpace));
            return objectItemCollection.GetClrType(oSpaceType); 
        }

        internal static ConstructorInfo GetConstructorInfo(Type type)
        { 
            Debug.Assert(null != type, "type required");
            ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, System.Type.EmptyTypes, null); 
 
            if (null == constructorInfo)
            { 
                throw new InvalidOperationException(Strings.DefaultConstructorNotFound(type));
            }

            return constructorInfo; 
        }
 
        internal static PropertyInfo GetPropertyInfo(Type type, string name) 
        {
            Debug.Assert(null != type, "type required"); 
            Debug.Assert(null != name, "name required");

            PropertyInfo propertyInfo = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, null, Type.EmptyTypes, null);
 
            if (null == propertyInfo)
            { 
                throw new InvalidOperationException(Strings.PropertyNotFound(name, type)); 
            }
 
            return propertyInfo;
        }

        internal static object InitializeType(Type type) 
        {
            ConstructorInfo constructorInfo = GetConstructorInfo(type); 
            return constructorInfo.Invoke(new object[] { }); 
        }
 
        /// 
        /// Given a data source column name, returns the corresponding Entity-SQL. If
        /// we are using the wrapper, we defer to the property descriptor to get
        /// the string. If there is no wrapper (or no corresponding property descriptor) 
        /// we use the column name directly.
        ///  
        /// Column name for which we produce a value expression. 
        /// Entity-SQL for column.
        internal static string GetEntitySqlValueForColumnName(string columnName, EntityDataSourceWrapperCollection wrapperCollection) 
        {
            Debug.Assert(!String.IsNullOrEmpty(columnName), "columnName must be given");

            string result = null; 

            if (wrapperCollection != null) 
            { 
                // use wrapper definition if it is available
                EntityDataSourceWrapperPropertyDescriptor descriptor = 
                    wrapperCollection.GetItemProperties(null).Find(columnName, false) as EntityDataSourceWrapperPropertyDescriptor;
                if (null != descriptor)
                {
                    result = descriptor.Column.GetEntitySqlValue(); 
                }
            } 
 
            // if descriptor does not provide SQL, create the default: it._columnName_
            if (null == result) 
            {
                result = EntitySqlElementAlias + "." + QuoteEntitySqlIdentifier(columnName);
            }
 
            return result;
        } 
 
        internal static Type ConvertTypeCodeToType(TypeCode typeCode)
        { 
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return typeof(Boolean); 

                case TypeCode.Byte: 
                    return typeof(Byte); 

                case TypeCode.Char: 
                    return typeof(Char);

                case TypeCode.DateTime:
                    return typeof(DateTime); 

                case TypeCode.DBNull: 
                    return typeof(DBNull); 

                case TypeCode.Decimal: 
                    return typeof(Decimal);

                case TypeCode.Double:
                    return typeof(Double); 

                case TypeCode.Empty: 
                    return null; 

                case TypeCode.Int16: 
                    return typeof(Int16);

                case TypeCode.Int32:
                    return typeof(Int32); 

                case TypeCode.Int64: 
                    return typeof(Int64); 

                case TypeCode.Object: 
                    return typeof(Object);

                case TypeCode.SByte:
                    return typeof(SByte); 

                case TypeCode.Single: 
                    return typeof(Single); 

                case TypeCode.String: 
                    return typeof(String);

                case TypeCode.UInt16:
                    return typeof(UInt16); 

                case TypeCode.UInt32: 
                    return typeof(UInt32); 

                case TypeCode.UInt64: 
                    return typeof(UInt64);

                default:
                    throw new InvalidOperationException(Strings.EntityDataSourceUtil_UnableToConvertTypeCodeToType(typeCode.ToString())); 
            }
        } 
 
        /// 
        /// Converts a DB type code to a CLR type, bypassing CLR type codes since there 
        /// is not a sufficient mapping.
        /// 
        /// The DB type to convert
        /// The mapped CLR type 
        internal static Type ConvertDbTypeToType(DbType dbType)
        { 
            switch (dbType) 
            {
                case DbType.AnsiString: 
                case DbType.AnsiStringFixedLength:
                case DbType.String:
                case DbType.StringFixedLength:
                    return typeof(String); 
                case DbType.Boolean:
                    return typeof(Boolean); 
                case DbType.Byte: 
                    return typeof(Byte);
                case DbType.VarNumeric:     // 
                case DbType.Currency:
                case DbType.Decimal:
                    return typeof(Decimal);
                case DbType.Date: 
                case DbType.DateTime:
                case DbType.DateTime2: // new Katmai type 
                    return typeof(DateTime); 
                case DbType.Time:      // new Katmai type
                    return typeof(TimeSpan); 
                case DbType.Double:
                    return typeof(Double);
                case DbType.Int16:
                    return typeof(Int16); 
                case DbType.Int32:
                    return typeof(Int32); 
                case DbType.Int64: 
                    return typeof(Int64);
                case DbType.SByte: 
                    return typeof(SByte);
                case DbType.Single:
                    return typeof(Single);
                case DbType.UInt16: 
                    return typeof(UInt16);
                case DbType.UInt32: 
                    return typeof(UInt32); 
                case DbType.UInt64:
                    return typeof(UInt64); 
                case DbType.Guid:
                    return typeof(Guid);
                case DbType.DateTimeOffset: // new Katmai type
                    return typeof(DateTimeOffset); 
                case DbType.Binary:
                    return typeof(byte[]); 
                case DbType.Object: 
                default:
                    return typeof(Object); 
            }
        }

        #endregion 

        #region Private helper method 
 
        private static IEnumerable GetTypeAndSubtypesOf(EdmType type, ReadOnlyCollection itemCollection, bool includeAbstractTypes)
            where T_EdmType : EdmType 
        {
            // Get the subtypes of the type from the WorkSpace
            T_EdmType specificType = type as T_EdmType;
            if (specificType != null) 
            {
 
                IEnumerable typesInWorkSpace = itemCollection.OfType(); 
                foreach (T_EdmType typeInWorkSpace in typesInWorkSpace)
                { 
                    if (specificType.Equals(typeInWorkSpace) == false && IsStrictSubtypeOf(typeInWorkSpace, specificType))
                    {
                        if (includeAbstractTypes || !typeInWorkSpace.Abstract)
                        { 
                            yield return typeInWorkSpace;
                        } 
 
                    }
                } 
            }
            yield break;
        }
 
        // requires: firstType is not null
        // effects: if otherType is among the base types, return true, 
        // otherwise returns false. 
        // when othertype is same as the current type, return false.
        private static bool IsStrictSubtypeOf(EdmType firstType, EdmType secondType) 
        {
            Debug.Assert(firstType != null, "firstType should not be not null");
            if (secondType == null)
            { 
                return false;
            } 
 
            // walk up my type hierarchy list
            for (EdmType t = firstType.BaseType; t != null; t = t.BaseType) 
            {
                if (t == secondType)
                    return true;
            } 
            return false;
        } 
 
        internal static bool NullCanBeAssignedTo(Type type)
        { 
            Debug.Assert(null != type, "type required");
            return !type.IsValueType || IsNullableType(type, out type);
        }
 
        internal static bool IsNullableType(Type type, out Type underlyingType)
        { 
            Debug.Assert(null != type, "type required"); 
            if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            { 
                underlyingType = type.GetGenericArguments()[0];
                return true;
            }
            underlyingType = null; 
            return false;
        } 
 
        internal static void ThrowArgumentNullException(string parameterName)
        { 
            throw ArgumentNull(parameterName);
        }

        internal static ArgumentNullException ArgumentNull(string parameter) 
        {
            ArgumentNullException e = new ArgumentNullException(parameter); 
            return e; 
        }
 
        internal static object ConvertType(object value, Type type, string paramName)
        {
            // NOTE: This method came from ObjectDataSource via LinqDataSource.
            // It has been changed to support better parsing of decimal values. 
            string s = value as string;
            if (s != null) 
            { 
                // Get the type converter for the destination type
                TypeConverter converter = TypeDescriptor.GetConverter(type); 
                if (converter != null)
                {
                    // Perform the conversion
                    try 
                    {
                        // If requested type is a decimal, then first try to parse using the Decimal parsing 
                        // which is able to handle comma thousands separators.  If this doesn't work, or 
                        // requested value is not a decimal, then fall back on the type converter mechanism.
                        decimal decimalResult; 
                        if (type.IsAssignableFrom(typeof(Decimal)) && Decimal.TryParse(s, out decimalResult))
                        {
                            value = decimalResult;
                        } 
                        else
                        { 
                            value = converter.ConvertFromString(s); 
                        }
                    } 
                    catch (Exception) // ConvertFromString sometimes throws exceptions of actual type Exception!
                    {
                        // For Nullable types, we just get the type parameter since that makes a more readable exception message
                        string typeName; 
                        if (type.IsGenericType && typeof(Nullable<>).IsAssignableFrom(type.GetGenericTypeDefinition()) && !type.ContainsGenericParameters)
                        { 
                            Type[] types = type.GetGenericArguments(); 
                            Debug.Assert(types != null && types.Length == 1, "Nullable did not have a single generic type.");
                            typeName = types[0].FullName; 
                        }
                        else
                        {
                            typeName = type.FullName; 
                        }
                        throw new InvalidOperationException(Strings.EntityDataSourceUtil_UnableToConvertStringToType(paramName, typeName)); 
                    } 
                }
            } 
            return value;
        }

        internal static void SetAllPropertiesWithVerification(EntityDataSourceWrapper entityWrapper, 
                                                              Dictionary changedProperties,
                                                              bool overwrite) 
        { 
            Dictionary exceptions = null;
            entityWrapper.SetAllProperties(changedProperties, /*overwriteSameValue*/true, ref exceptions); 

            if (null != exceptions)
            {
                // The EntityDataSourceValidationException has a property "InnerExceptions" that encapsulates 
                // all of the failed property setters. The message from one of those errors is surfaced so that it
                // appears on the web page as a human-readable error like: 
                //   "Error while setting property 'PropertyName': 'The value cannot be null.'." 
                string key = exceptions.Keys.First();
                throw new EntityDataSourceValidationException( 
                    Strings.EntityDataSourceView_DataConversionError(
                        key, exceptions[key].Message), exceptions);
            }
        } 

        ///  
        /// Get the Clr type for the primitive or complex type member. The member must not be null. 
        /// 
        internal static Type GetMemberClrType(MetadataWorkspace ocWorkspace, EdmMember member) 
        {
            EntityDataSourceUtil.CheckArgumentNull(member, "member");

            EdmType memberType = member.TypeUsage.EdmType; 

            Debug.Assert(memberType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType || 
                memberType.BuiltInTypeKind == BuiltInTypeKind.ComplexType || 
                memberType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "member type must be primitive, entity or complex type");
 
            Type clrType;

            if (memberType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
            { 
                PrimitiveType primitiveType = (PrimitiveType)memberType;
 
                clrType = primitiveType.ClrEquivalentType; 

                if (!NullCanBeAssignedTo(clrType)) 
                {
                    Facet facet;
                    if (member.TypeUsage.Facets.TryGetValue("Nullable", true, out facet))
                    { 
                        if ((bool)facet.Value)
                        { 
                            clrType = MakeNullable(clrType); 
                        }
                    } 
                }
            }
            else if (memberType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
            { 
                EntityType entityType = (EntityType)memberType;
 
                clrType = GetClrType(ocWorkspace, entityType); 
            }
            else 
            {
                ComplexType complexType = (ComplexType)memberType;

                clrType = GetClrType(ocWorkspace, complexType); 
            }
 
            return clrType; 
        }
 
        /// Get the Clr type for the primitive type member. The member must not be null.
        internal static Type GetPrimitiveMemberClrType(EdmMember member)
        {
            Debug.Assert(member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "member must be primitive member"); 

            MetadataWorkspace ocWorkspace = null; // workspace is not required to determine CLR primitive type 
 
            return GetMemberClrType(ocWorkspace, member);
        } 

        internal static Type MakeNullable(Type type)
        {
            if (!NullCanBeAssignedTo(type)) 
            {
                type = typeof(Nullable<>).MakeGenericType(type); 
            } 
            return type;
        } 

        /// 
        /// Returns the collection of AssociationSetEnds for the relationships for this entity
        ///  
        /// 
        ///  
        /// If true, returns only the other ends with multiplicity 1. Ignores 1:0..1 relationships. 
        /// 
        internal static IEnumerable GetReferenceEnds(EntitySet entitySet, EntityType entityType, bool forKey) 
        {
            foreach (AssociationSet associationSet in entitySet.EntityContainer.BaseEntitySets.OfType())
            {
                Debug.Assert(associationSet.AssociationSetEnds.Count == 2, "non binary association?"); 
                AssociationSetEnd firstEnd = associationSet.AssociationSetEnds[0];
                AssociationSetEnd secondEnd = associationSet.AssociationSetEnds[1]; 
 
                // If both ends match, then we will return both ends
                if (IsReferenceEnd(entitySet, entityType, firstEnd, secondEnd, forKey)) 
                {
                    yield return secondEnd;
                }
                if (IsReferenceEnd(entitySet, entityType, secondEnd, firstEnd, forKey)) 
                {
                    yield return firstEnd; 
                } 
            }
        } 

        /// 
        /// Determine if the end is 'contained' in the source entity via a referential integrity constraint (e.g.,
        /// in a relationship from OrderDetail to Order where OrderDetail has the OrderId property, the association set end 
        /// is contained in the order detail entity)
        ///  
        private static bool IsContained(AssociationSetEnd end, out ReferentialConstraint constraint) 
        {
            CheckArgumentNull(end, "end"); 

            AssociationEndMember endMember = end.CorrespondingAssociationEndMember;
            AssociationType associationType = (AssociationType)endMember.DeclaringType;
 
            constraint = null;
            bool result = false; 
 
            if (null != associationType.ReferentialConstraints)
            { 
                foreach (ReferentialConstraint candidate in associationType.ReferentialConstraints)
                {
                    if (candidate.FromRole.Name == endMember.Name)
                    { 
                        constraint = candidate;
                        result = true; 
                        break; 
                    }
                } 
            }

            return result;
        } 

        internal static bool TryGetCorrespondingNavigationProperty(AssociationEndMember end, out NavigationProperty navigationProperty) 
        { 
            EntityType entityType = GetEntityType(GetOppositeEnd(end));
 
            // if there is a corresponding navigation property, use its name as the prefix
            navigationProperty = entityType.NavigationProperties
                .Where(np => np.ToEndMember == end)
                .SingleOrDefault(); // metadata is supposed to ensure this is non-ambiguous 
            return null != navigationProperty;
        } 
 
        internal static AssociationEndMember GetOppositeEnd(AssociationEndMember end)
        { 
            return (AssociationEndMember)end.DeclaringType.Members.Where(m => m != end).Single();
        }

        ///  
        /// A navigation ('fromEnd' -> 'toEnd') defines a reference end for 'entitySet' and 'entityType' if it
        /// has multiplicity 0..1 or 1..1, is bound to the set, and has the appropriate type. 
        /// 
        /// We omit 1..1:0..1 navigations assuming that the opposite end owns the relationship (since the foreign
        /// key would need to point in the opposite direction.) 
        /// 
        private static bool IsReferenceEnd(EntitySet entitySet, EntityType entityType, AssociationSetEnd fromEnd, AssociationSetEnd toEnd, bool forKey)
        {
            EntityType fromType = GetEntityType(fromEnd); 

            if (fromEnd.EntitySet == entitySet && (IsStrictSubtypeOf(entityType, fromType) || entityType == fromType)) 
            { 
                RelationshipMultiplicity fromMult = fromEnd.CorrespondingAssociationEndMember.RelationshipMultiplicity;
                RelationshipMultiplicity toMult = toEnd.CorrespondingAssociationEndMember.RelationshipMultiplicity; 

                // If forKey is false (we are testing to see if this is a far end for a reference, not a key)
                //   then fromMult is ignored and all far-end 1 or 0..1 multiplicity ends are exposed.
                // If forKey is true, then we are asking about a reference end for the purpose of flattening. 
                //   We do not flatten 1:0..1 relationships because of a limitation in the EDM.
                if (toMult == RelationshipMultiplicity.One || 
                    (toMult == RelationshipMultiplicity.ZeroOrOne && (!forKey || fromMult != RelationshipMultiplicity.One) )) 
                {
                    return true; 
                }
            }

            return false; 
        }
 
        internal static EntityType GetEntityType(AssociationSetEnd end) 
        {
            return GetEntityType(end.CorrespondingAssociationEndMember); 
        }

        internal static EntityType GetEntityType(AssociationEndMember end)
        { 
            EntityType entityType = (EntityType)((RefType)end.TypeUsage.EdmType).ElementType;
            return entityType; 
        } 

        internal static string GetQualifiedEntitySetName(EntitySet entitySet) 
        {
            EntityDataSourceUtil.CheckArgumentNull(entitySet, "entitySet");
            // ContainerName.EntitySetName
            return entitySet.EntityContainer.Name + "." + entitySet.Name; 
        }
 
        internal static string QuoteEntitySqlIdentifier(string identifier) 
        {
            return "[" + (identifier ?? string.Empty).Replace("]", "]]") + "]"; 
        }

        internal static string CreateEntitySqlTypeIdentifier(EdmType type)
        { 
            // [_schema_namespace_name_].[_type_name_]
            return QuoteEntitySqlIdentifier(type.NamespaceName) + "." + QuoteEntitySqlIdentifier(type.Name); 
        } 

        internal static string CreateEntitySqlSetIdentifier(EntitySetBase set) 
        {
            // [_container_name_].[_set_name_]
            return QuoteEntitySqlIdentifier(set.EntityContainer.Name) + "." + QuoteEntitySqlIdentifier(set.Name);
        } 

        ///  
        /// Determines which columns to expose for the given set and type. Includes 
        /// flattened complex properties and 'reference' keys.
        ///  
        /// Used to determine 'interesting' members, or
        /// members whose values need to be maintained in ControlState
        /// Used to get CLR mapping information for EDM
        /// types 
        /// The set.
        /// The type. 
        /// A map from display names to columns. 
        internal static ReadOnlyCollection GetNamedColumns(MetadataWorkspace csWorkspace, MetadataWorkspace ocWorkspace,
            EntitySet entitySet, EntityType entityType) 
        {
            CheckArgumentNull(csWorkspace, "csWorkspace");
            CheckArgumentNull(ocWorkspace, "ocWorkspace");
            CheckArgumentNull(entitySet, "entitySet"); 
            CheckArgumentNull(entityType, "entityType");
 
            ReadOnlyCollection interestingMembers = GetInterestingMembers(csWorkspace, entitySet, entityType); 

            IEnumerable columns = GetColumns(entitySet, entityType, ocWorkspace, interestingMembers); 
            List result = new List();

            // give precedence to simple named columns (
 
            HashSet usedNames = new HashSet();
            foreach (EntityDataSourceColumn column in columns) 
            { 
                if (!column.IsHidden)
                { 
                    // check that the column name has not been used
                    if (!usedNames.Add(column.DisplayName))
                    {
                        throw new InvalidOperationException(Strings.DisplayNameCollision(column.DisplayName)); 
                    }
                } 
                result.Add(column); 
            }
 
            return result.AsReadOnly();
        }

        private static ReadOnlyCollection GetInterestingMembers(MetadataWorkspace csWorkspace, EntitySet entitySet, EntityType entityType) 
        {
            // Note that this delegate is not used to determine whether reference columns are interesting. They 
            // are intrinsically interesting and do not appear in this set. 
            HashSet interestingMembers = new HashSet(
                csWorkspace.GetRequiredOriginalValueMembers(entitySet, entitySet.ElementType)); 

            // keys are also interesting...
            foreach (EdmMember keyMember in entityType.KeyMembers)
            { 
                interestingMembers.Add(keyMember);
            } 
 
            // complex properties are also interesting
            foreach (EdmMember member in entityType.Members) 
            {
                if (member.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                {
                    interestingMembers.Add(member); 
                }
            } 
 

            ReadOnlyCollection result = interestingMembers.ToList().AsReadOnly(); 

            return result;
        }
 
        private static IEnumerable GetColumns(EntitySet entitySet, EntityType entityType,
            MetadataWorkspace ocWorkspace, ReadOnlyCollection interestingMembers) 
        { 
            List columns = new List();
 
            // Primitive and complex properties
            EntityDataSourceMemberPath parent = null; // top-level properties are not qualified
            Dictionary entityProperties = AddPropertyColumns(columns, ocWorkspace, parent, entityType.Properties, interestingMembers);
 
            // Navigation reference properties
            AddReferenceNavigationColumns(columns, ocWorkspace, entitySet, entityType); 
 
            // Reference key properties
            AddReferenceKeyColumns(columns, ocWorkspace, entitySet, entityType, entityProperties); 

            return columns;
        }
 
        // Adds element to 'columns' for every element of 'properties'. Also returns a map from properties
        // at this level to the corresponding columns. 
        private static Dictionary AddPropertyColumns(List columns, MetadataWorkspace ocWorkspace, EntityDataSourceMemberPath parent, IEnumerable properties, ReadOnlyCollection interestingMembers) 
        {
            Dictionary result = new Dictionary(); 

            foreach (EdmProperty property in properties)
            {
                bool isLocallyInteresting = interestingMembers.Contains(property); 

                EntityDataSourceMemberPath prefix = new EntityDataSourceMemberPath(ocWorkspace, parent, property, isLocallyInteresting); 
                EdmType propertyType = property.TypeUsage.EdmType; 

                // add column for this entity property 
                EntityDataSourcePropertyColumn propertyColumn = new EntityDataSourcePropertyColumn(prefix);
                columns.Add(propertyColumn);
                result.Add(property, propertyColumn);
 
                if (propertyType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                { 
                    // add nested properties 
                    // prepend the property name to the members of the complex type
                    AddPropertyColumns(columns, ocWorkspace, prefix, ((ComplexType)propertyType).Properties, interestingMembers); 
                }
                // other property types are not currently supported (or possible in EF V1 for that matter)
            }
 
            return result;
        } 
 
        private static void AddReferenceNavigationColumns(List columns, MetadataWorkspace ocWorkspace, EntitySet entitySet, EntityType entityType)
        { 
            foreach (AssociationSetEnd toEnd in GetReferenceEnds(entitySet, entityType, /*forKey*/false))
            {
                // Check for a navigation property
                NavigationProperty navigationProperty; 
                if (TryGetCorrespondingNavigationProperty(toEnd.CorrespondingAssociationEndMember, out navigationProperty))
                { 
                    Type clrToType = EntityDataSourceUtil.GetMemberClrType(ocWorkspace, navigationProperty); 
                    EntityDataSourceReferenceValueColumn column = EntityDataSourceReferenceValueColumn.Create(clrToType, ocWorkspace, navigationProperty);
                    columns.Add(column); 
                }
            }
        }
 
        private static void AddReferenceKeyColumns(List columns, MetadataWorkspace ocWorkspace, EntitySet entitySet, EntityType entityType, Dictionary entityProperties)
        { 
            foreach (AssociationSetEnd toEnd in GetReferenceEnds(entitySet, entityType, /*forKey*/true)) 
            {
                ReferentialConstraint constraint; 
                bool isContained = EntityDataSourceUtil.IsContained(toEnd, out constraint);

                    // Create a group for the end columns
                    EntityType toType = EntityDataSourceUtil.GetEntityType(toEnd); 
                    Type clrToType = EntityDataSourceUtil.GetClrType(ocWorkspace, toType);
 
                    EntityDataSourceReferenceGroup group = EntityDataSourceReferenceGroup.Create(clrToType, toEnd); 

                    // Create a column for every key 
                    foreach (EdmProperty keyMember in GetEntityType(toEnd).KeyMembers)
                    {
                        EntityDataSourceColumn controllingColumn = null;
                        if (isContained) 
                        {
                            // if this key is 'contained' in the entity, make the referential constrained 
                            // property the principal for the column 
                            int ordinalInConstraint = constraint.FromProperties.IndexOf(keyMember);
 
                            // find corresponding member in the current (dependent) entity
                            EdmProperty correspondingProperty = constraint.ToProperties[ordinalInConstraint];

                            controllingColumn = entityProperties[correspondingProperty]; 
                        }
                        columns.Add(new EntityDataSourceReferenceKeyColumn(group, keyMember, controllingColumn)); 
                    } 
            }
        } 

        #endregion

    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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