Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWebControls / System / Data / WebControls / EntityDataSourceUtil.cs / 2 / 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; 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())); } } ////// This code is copied verbatim from System.Web.UI.WebControls.Parameter.cs /// /// ///internal static TypeCode ConvertDbTypeToTypeCode(DbType dbType) { switch (dbType) { case DbType.AnsiString: case DbType.AnsiStringFixedLength: case DbType.String: case DbType.StringFixedLength: return TypeCode.String; case DbType.Boolean: return TypeCode.Boolean; case DbType.Byte: return TypeCode.Byte; case DbType.VarNumeric: // case DbType.Currency: case DbType.Decimal: return TypeCode.Decimal; case DbType.Date: case DbType.DateTime: case DbType.DateTime2: // new Katmai type case DbType.Time: // new Katmai type - no TypeCode for TimeSpan return TypeCode.DateTime; case DbType.Double: return TypeCode.Double; case DbType.Int16: return TypeCode.Int16; case DbType.Int32: return TypeCode.Int32; case DbType.Int64: return TypeCode.Int64; case DbType.SByte: return TypeCode.SByte; case DbType.Single: return TypeCode.Single; case DbType.UInt16: return TypeCode.UInt16; case DbType.UInt32: return TypeCode.UInt32; case DbType.UInt64: return TypeCode.UInt64; case DbType.Guid: // ??? case DbType.Binary: case DbType.Object: case DbType.DateTimeOffset: // new Katmai type - no TypeCode for DateTimeOffset default: return TypeCode.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. 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 { value = converter.ConvertFromString(s); } catch (NotSupportedException) { throw new InvalidOperationException(Strings.CannotConvertType(paramName, s, type.ToString())); } catch (FormatException) { throw new InvalidOperationException(Strings.CannotConvertType(paramName, s, type.ToString())); } } } 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 ReadOnlyCollectionGetNamedColumns(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; 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())); } } ////// This code is copied verbatim from System.Web.UI.WebControls.Parameter.cs /// /// ///internal static TypeCode ConvertDbTypeToTypeCode(DbType dbType) { switch (dbType) { case DbType.AnsiString: case DbType.AnsiStringFixedLength: case DbType.String: case DbType.StringFixedLength: return TypeCode.String; case DbType.Boolean: return TypeCode.Boolean; case DbType.Byte: return TypeCode.Byte; case DbType.VarNumeric: // case DbType.Currency: case DbType.Decimal: return TypeCode.Decimal; case DbType.Date: case DbType.DateTime: case DbType.DateTime2: // new Katmai type case DbType.Time: // new Katmai type - no TypeCode for TimeSpan return TypeCode.DateTime; case DbType.Double: return TypeCode.Double; case DbType.Int16: return TypeCode.Int16; case DbType.Int32: return TypeCode.Int32; case DbType.Int64: return TypeCode.Int64; case DbType.SByte: return TypeCode.SByte; case DbType.Single: return TypeCode.Single; case DbType.UInt16: return TypeCode.UInt16; case DbType.UInt32: return TypeCode.UInt32; case DbType.UInt64: return TypeCode.UInt64; case DbType.Guid: // ??? case DbType.Binary: case DbType.Object: case DbType.DateTimeOffset: // new Katmai type - no TypeCode for DateTimeOffset default: return TypeCode.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. 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 { value = converter.ConvertFromString(s); } catch (NotSupportedException) { throw new InvalidOperationException(Strings.CannotConvertType(paramName, s, type.ToString())); } catch (FormatException) { throw new InvalidOperationException(Strings.CannotConvertType(paramName, s, type.ToString())); } } } 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 ReadOnlyCollectionGetNamedColumns(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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- storagemappingitemcollection.viewdictionary.cs
- PropertyGeneratedEventArgs.cs
- DataTemplate.cs
- InstanceContextManager.cs
- RegisteredExpandoAttribute.cs
- assertwrapper.cs
- XmlImplementation.cs
- InsufficientMemoryException.cs
- LinqDataSourceSelectEventArgs.cs
- MenuAutomationPeer.cs
- ObjectStateEntryDbDataRecord.cs
- SafeSystemMetrics.cs
- ControlBuilder.cs
- EdmItemError.cs
- WindowsToolbarAsMenu.cs
- SrgsSubset.cs
- SeekableReadStream.cs
- NavigationPropertyEmitter.cs
- ObjectItemCollection.cs
- BitmapEffectState.cs
- StoreContentChangedEventArgs.cs
- DeploymentSectionCache.cs
- TextComposition.cs
- UxThemeWrapper.cs
- OracleConnectionStringBuilder.cs
- Char.cs
- AssertFilter.cs
- Encoding.cs
- CommonDialog.cs
- DataGridCell.cs
- DeobfuscatingStream.cs
- TypeValidationEventArgs.cs
- CompositeCollection.cs
- DataGridCaption.cs
- DiscreteKeyFrames.cs
- TemplateControlBuildProvider.cs
- DoubleAverageAggregationOperator.cs
- SmiConnection.cs
- DataKeyArray.cs
- SqlBooleanizer.cs
- SessionStateUtil.cs
- VariantWrapper.cs
- HtmlInputText.cs
- HwndKeyboardInputProvider.cs
- GeometryGroup.cs
- SchemaSetCompiler.cs
- Utils.cs
- ConnectionOrientedTransportManager.cs
- SmiMetaDataProperty.cs
- Win32Exception.cs
- TempFiles.cs
- QuestionEventArgs.cs
- DictionaryItemsCollection.cs
- EntityCollectionChangedParams.cs
- CounterCreationDataCollection.cs
- GenericEnumConverter.cs
- DataRecordInfo.cs
- MemberDomainMap.cs
- TreeViewImageIndexConverter.cs
- SqlNotificationRequest.cs
- ListViewInsertedEventArgs.cs
- EndpointReference.cs
- Utils.cs
- RightsManagementInformation.cs
- ConnectionProviderAttribute.cs
- IntSecurity.cs
- ProgressBarRenderer.cs
- HttpListenerRequest.cs
- DecimalStorage.cs
- MediaSystem.cs
- IItemContainerGenerator.cs
- SamlAttribute.cs
- Pair.cs
- HwndMouseInputProvider.cs
- Vector3DCollectionConverter.cs
- RangeBase.cs
- DataTransferEventArgs.cs
- ReflectionPermission.cs
- SiteIdentityPermission.cs
- XmlArrayAttribute.cs
- PropertyTab.cs
- XmlDataProvider.cs
- DataGridViewSelectedCellsAccessibleObject.cs
- WmlValidatorAdapter.cs
- ImageListUtils.cs
- TracePayload.cs
- UIElement3D.cs
- StreamGeometryContext.cs
- namescope.cs
- ToolBarButtonClickEvent.cs
- AdjustableArrowCap.cs
- WinFormsSpinner.cs
- ContextMenu.cs
- CategoryValueConverter.cs
- SettingsSection.cs
- UnsettableComboBox.cs
- FloaterParaClient.cs
- MgmtResManager.cs
- FirstMatchCodeGroup.cs
- IsolatedStorage.cs