/// <summary> /// "Explode" a root type. (ie) add each member of the type to a flat list of /// members for the supertype. /// /// Type explosion works in a DFS style model. We first walk through the /// list of properties for the current type, and "flatten" out the properties /// that are themselves "structured". We then target each subtype (recursively) /// and perform the same kind of processing. /// /// Consider a very simple case: /// /// Q = (z1 int, z2 date) /// Q2: Q = (z3 string) -- Q2 is a subtype of Q /// T = (a int, b Q, c date) /// S: T = (d int) -- read as S is a subtype of T /// /// The result of flattening T (and S) will be /// /// (a int, b.z1 int, b.z2 date, b.z3 string, c date, d int) /// </summary> /// <param name="rootType">the root type to explode</param> private void ExplodeRootStructuredType(RootTypeInfo rootType) { // Already done?? if (rootType.FlattenedType != null) { return; } // // Special handling for root types. Add any special // properties that are needed - TypeId, EntitySetId, etc // if (NeedsTypeIdProperty(rootType)) { rootType.AddPropertyRef(TypeIdPropertyRef.Instance); // check for discriminator map; if one exists, use custom discriminator member; otherwise, use default if (null != rootType.DiscriminatorMap) { rootType.TypeIdKind = TypeIdKind.UserSpecified; rootType.TypeIdType = md.Helper.GetModelTypeUsage(rootType.DiscriminatorMap.DiscriminatorProperty); } else { rootType.TypeIdKind = TypeIdKind.Generated; rootType.TypeIdType = m_stringType; } } if (NeedsEntitySetIdProperty(rootType)) { rootType.AddPropertyRef(EntitySetIdPropertyRef.Instance); } if (NeedsNullSentinelProperty(rootType)) { rootType.AddPropertyRef(NullSentinelPropertyRef.Instance); } // // Then add members from each type in the hierarchy (including // the root type) // ExplodeRootStructuredTypeHelper(rootType); // // For entity types, add all the rel-properties now. Note that rel-properties // are added after the regular properties of all subtypes // if (md.TypeSemantics.IsEntityType(rootType.Type)) { AddRelProperties(rootType); } // // We've now gotten all the relevant properties // Now let's create a new record type // CreateFlattenedRecordType(rootType); }
/// <summary> /// Helper for ExplodeType. /// Walks through each member introduced by the current type, and /// adds it onto the "flat" record type being constructed. /// We then walk through all subtypes of this type, and process those as /// well. /// Special handling for Refs: we only add the keys; there is no /// need to handle subtypes (since they won't be introducing anything /// different) /// </summary> /// <param name="typeInfo">type in the type hierarchy</param> private void ExplodeRootStructuredTypeHelper(TypeInfo typeInfo) { RootTypeInfo rootType = typeInfo.RootType; // Identify the members of this type. For Refs, use the key properties // of the target entity type. For all other types, simply use the type // members IEnumerable typeMembers = null; md.RefType refType; if (TypeHelpers.TryGetEdmType <md.RefType>(typeInfo.Type, out refType)) { // // If this is not the root type, then don't bother adding the keys. // the root type has already done this // if (!typeInfo.IsRootType) { return; } typeMembers = refType.ElementType.KeyMembers; } else { typeMembers = TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type); } // Walk through all the members of the type foreach (md.EdmMember p in typeMembers) { TypeInfo propertyType = ExplodeType(p.TypeUsage); // // If we can't find a TypeInfo for this property's type, then it must // be a scalar type or a collection type. In either case, we'll // build up a SimplePropertyRef // if (propertyType == null) { rootType.AddPropertyRef(new SimplePropertyRef(p)); } else { // // We're dealing with a structured type again. Create NestedPropertyRef // for each property of the nested type // foreach (PropertyRef nestedPropInfo in propertyType.PropertyRefList) { rootType.AddPropertyRef(nestedPropInfo.CreateNestedPropertyRef(p)); } } } // // Process all subtypes now // foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) { ExplodeRootStructuredTypeHelper(subTypeInfo); } }
/// <summary> /// "Explode" a root type. (ie) add each member of the type to a flat list of /// members for the supertype. /// /// Type explosion works in a DFS style model. We first walk through the /// list of properties for the current type, and "flatten" out the properties /// that are themselves "structured". We then target each subtype (recursively) /// and perform the same kind of processing. /// /// Consider a very simple case: /// /// Q = (z1 int, z2 date) /// Q2: Q = (z3 string) -- Q2 is a subtype of Q /// T = (a int, b Q, c date) /// S: T = (d int) -- read as S is a subtype of T /// /// The result of flattening T (and S) will be /// /// (a int, b.z1 int, b.z2 date, b.z3 string, c date, d int) /// </summary> /// <param name="rootType">the root type to explode</param> private void ExplodeRootStructuredType(RootTypeInfo rootType) { // Already done?? if (rootType.FlattenedType != null) { return; } // // Special handling for root types. Add any special // properties that are needed - TypeId, EntitySetId, etc // if (NeedsTypeIdProperty(rootType)) { rootType.AddPropertyRef(TypeIdPropertyRef.Instance); // check for discriminator map; if one exists, use custom discriminator member; otherwise, use default if (null != rootType.DiscriminatorMap) { rootType.TypeIdKind = TypeIdKind.UserSpecified; rootType.TypeIdType = md.Helper.GetModelTypeUsage(rootType.DiscriminatorMap.DiscriminatorProperty); } else { rootType.TypeIdKind = TypeIdKind.Generated; rootType.TypeIdType = m_stringType; } } if (NeedsEntitySetIdProperty(rootType)) { rootType.AddPropertyRef(EntitySetIdPropertyRef.Instance); } if (NeedsNullSentinelProperty(rootType)) { rootType.AddPropertyRef(NullSentinelPropertyRef.Instance); } // // Then add members from each type in the hierarchy (including // the root type) // ExplodeRootStructuredTypeHelper(rootType); // // For entity types, add all the rel-properties now. Note that rel-properties // are added after the regular properties of all subtypes // if (md.TypeSemantics.IsEntityType(rootType.Type)) { AddRelProperties(rootType); } // // We've now gotten all the relevant properties // Now let's create a new record type // CreateFlattenedRecordType(rootType); }