/// <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> /// Get the datatype for a propertyRef. The only concrete classes that we /// handle are TypeIdPropertyRef, and BasicPropertyRef. /// AllPropertyRef is illegal here. /// For BasicPropertyRef, we simply pick up the type from the corresponding /// property. For TypeIdPropertyRef, we use "string" as the default type /// or the discriminator property type where one is available. /// </summary> /// <param name="typeInfo">typeinfo of the current type</param> /// <param name="p">current property ref</param> /// <returns>the datatype of the property</returns> private md.TypeUsage GetPropertyType(RootTypeInfo typeInfo, PropertyRef p) { md.TypeUsage result = null; PropertyRef innerProperty = null; // Get the "leaf" property first while (p is NestedPropertyRef) { NestedPropertyRef npr = (NestedPropertyRef)p; p = npr.OuterProperty; innerProperty = npr.InnerProperty; } if (p is TypeIdPropertyRef) { // // Get to the innermost type that specifies this typeid (the entity type), // get the datatype for the typeid column from that type // if (innerProperty != null && innerProperty is SimplePropertyRef) { md.TypeUsage innerType = ((SimplePropertyRef)innerProperty).Property.TypeUsage; TypeInfo innerTypeInfo = GetTypeInfo(innerType); result = innerTypeInfo.RootType.TypeIdType; } else { result = typeInfo.TypeIdType; } } else if (p is EntitySetIdPropertyRef || p is NullSentinelPropertyRef) { result = m_intType; } else if (p is RelPropertyRef) { result = (p as RelPropertyRef).Property.ToEnd.TypeUsage; } else { SimplePropertyRef simpleP = p as SimplePropertyRef; if (simpleP != null) { result = md.Helper.GetModelTypeUsage(simpleP.Property); } } result = GetNewType(result); PlanCompiler.Assert(null != result, "unrecognized property type?"); return(result); }
protected TypeInfo(md.TypeUsage type, TypeInfo superType) { m_type = type; m_immediateSubTypes = new List <TypeInfo>(); m_superType = superType; if (superType != null) { // Add myself to my supertype's list of subtypes superType.m_immediateSubTypes.Add(this); // my supertype's root type is mine as well m_rootType = superType.RootType; } }
private readonly RootTypeInfo m_rootType; // the top-most type in this types type hierarchy #endregion #region Constructors and factory methods /// <summary> /// Creates type information for a type /// </summary> /// <param name="type"></param> /// <param name="superTypeInfo"></param> /// <returns></returns> internal static TypeInfo Create(md.TypeUsage type, TypeInfo superTypeInfo, ExplicitDiscriminatorMap discriminatorMap) { TypeInfo result; if (superTypeInfo == null) { result = new RootTypeInfo(type, discriminatorMap); } else { result = new TypeInfo(type, superTypeInfo); } return result; }
protected TypeInfo(md.TypeUsage type, TypeInfo superType) { m_type = type; m_immediateSubTypes = new List<TypeInfo>(); m_superType = superType; if (superType != null) { // Add myself to my supertype's list of subtypes superType.m_immediateSubTypes.Add(this); // my supertype's root type is mine as well m_rootType = superType.RootType; } }
private readonly RootTypeInfo m_rootType; // the top-most type in this types type hierarchy #endregion #region Constructors and factory methods /// <summary> /// Creates type information for a type /// </summary> /// <param name="type"></param> /// <param name="superTypeInfo"></param> /// <returns></returns> internal static TypeInfo Create(md.TypeUsage type, TypeInfo superTypeInfo, ExplicitDiscriminatorMap discriminatorMap) { TypeInfo result; if (superTypeInfo == null) { result = new RootTypeInfo(type, discriminatorMap); } else { result = new TypeInfo(type, superTypeInfo); } return(result); }
/// <summary> /// Create the flattened record type for the type. /// Walk through the list of property refs, and creates a new field /// (which we name as "F1", "F2" etc.) with the required property type. /// /// We then produce a mapping from the original property (propertyRef really) /// to the new property for use in later modules. /// /// Finally, we identify the TypeId and EntitySetId property if they exist /// </summary> /// <param name="type"></param> private void CreateFlattenedRecordType(RootTypeInfo type) { // // If this type corresponds to an entity type, and that entity type // has no subtypes, and that that entity type has no complex properties // then simply use the name from that property // bool usePropertyNamesFromUnderlyingType; if (md.TypeSemantics.IsEntityType(type.Type) && type.ImmediateSubTypes.Count == 0) { usePropertyNamesFromUnderlyingType = true; } else { usePropertyNamesFromUnderlyingType = false; } // Build the record type List <KeyValuePair <string, md.TypeUsage> > fieldList = new List <KeyValuePair <string, md.TypeUsage> >(); HashSet <string> fieldNames = new HashSet <string>(); int nextFieldId = 0; foreach (PropertyRef p in type.PropertyRefList) { string fieldName = null; if (usePropertyNamesFromUnderlyingType) { SimplePropertyRef simpleP = p as SimplePropertyRef; if (simpleP != null) { fieldName = simpleP.Property.Name; } } if (fieldName == null) { fieldName = "F" + nextFieldId.ToString(CultureInfo.InvariantCulture); nextFieldId++; } // Deal with collisions while (fieldNames.Contains(fieldName)) { fieldName = "F" + nextFieldId.ToString(CultureInfo.InvariantCulture); nextFieldId++; } md.TypeUsage propertyType = GetPropertyType(type, p); fieldList.Add(new KeyValuePair <string, md.TypeUsage>(fieldName, propertyType)); fieldNames.Add(fieldName); } type.FlattenedType = TypeHelpers.CreateRowType(fieldList); // Now build up the property map IEnumerator <PropertyRef> origProps = type.PropertyRefList.GetEnumerator(); foreach (md.EdmProperty p in type.FlattenedType.Properties) { if (!origProps.MoveNext()) { PlanCompiler.Assert(false, "property refs count and flattened type member count mismatch?"); } type.AddPropertyMapping(origProps.Current, p); } }
/// <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> /// Create the flattened record type for the type. /// Walk through the list of property refs, and creates a new field /// (which we name as "F1", "F2" etc.) with the required property type. /// /// We then produce a mapping from the original property (propertyRef really) /// to the new property for use in later modules. /// /// Finally, we identify the TypeId and EntitySetId property if they exist /// </summary> /// <param name="type"></param> private void CreateFlattenedRecordType(RootTypeInfo type) { // // If this type corresponds to an entity type, and that entity type // has no subtypes, and that that entity type has no complex properties // then simply use the name from that property // bool usePropertyNamesFromUnderlyingType; if (md.TypeSemantics.IsEntityType(type.Type) && type.ImmediateSubTypes.Count == 0) { usePropertyNamesFromUnderlyingType = true; } else { usePropertyNamesFromUnderlyingType = false; } // Build the record type List<KeyValuePair<string, md.TypeUsage>> fieldList = new List<KeyValuePair<string, md.TypeUsage>>(); HashSet<string> fieldNames = new HashSet<string>(); int nextFieldId = 0; foreach (PropertyRef p in type.PropertyRefList) { string fieldName = null; if (usePropertyNamesFromUnderlyingType) { SimplePropertyRef simpleP = p as SimplePropertyRef; if (simpleP != null) { fieldName = simpleP.Property.Name; } } if (fieldName == null) { fieldName = "F" + nextFieldId.ToString(CultureInfo.InvariantCulture); nextFieldId++; } // Deal with collisions while (fieldNames.Contains(fieldName)) { fieldName = "F" + nextFieldId.ToString(CultureInfo.InvariantCulture); nextFieldId++; } md.TypeUsage propertyType = GetPropertyType(type, p); fieldList.Add(new KeyValuePair<string, md.TypeUsage>(fieldName, propertyType)); fieldNames.Add(fieldName); } type.FlattenedType = TypeHelpers.CreateRowType(fieldList); // Now build up the property map IEnumerator<PropertyRef> origProps = type.PropertyRefList.GetEnumerator(); foreach (md.EdmProperty p in type.FlattenedType.Properties) { if (!origProps.MoveNext()) { PlanCompiler.Assert(false, "property refs count and flattened type member count mismatch?"); } type.AddPropertyMapping(origProps.Current, p); } }
/// <summary> /// Get the datatype for a propertyRef. The only concrete classes that we /// handle are TypeIdPropertyRef, and BasicPropertyRef. /// AllPropertyRef is illegal here. /// For BasicPropertyRef, we simply pick up the type from the corresponding /// property. For TypeIdPropertyRef, we use "string" as the default type /// or the discriminator property type where one is available. /// </summary> /// <param name="typeInfo">typeinfo of the current type</param> /// <param name="p">current property ref</param> /// <returns>the datatype of the property</returns> private md.TypeUsage GetPropertyType(RootTypeInfo typeInfo, PropertyRef p) { md.TypeUsage result = null; PropertyRef innerProperty = null; // Get the "leaf" property first while (p is NestedPropertyRef) { NestedPropertyRef npr = (NestedPropertyRef)p; p = npr.OuterProperty; innerProperty = npr.InnerProperty; } if (p is TypeIdPropertyRef) { // // Get to the innermost type that specifies this typeid (the entity type), // get the datatype for the typeid column from that type // if (innerProperty != null && innerProperty is SimplePropertyRef) { md.TypeUsage innerType = ((SimplePropertyRef)innerProperty).Property.TypeUsage; TypeInfo innerTypeInfo = GetTypeInfo(innerType); result = innerTypeInfo.RootType.TypeIdType; } else { result = typeInfo.TypeIdType; } } else if (p is EntitySetIdPropertyRef || p is NullSentinelPropertyRef) { result = m_intType; } else if (p is RelPropertyRef) { result = (p as RelPropertyRef).Property.ToEnd.TypeUsage; } else { SimplePropertyRef simpleP = p as SimplePropertyRef; if (simpleP != null) { result = md.Helper.GetModelTypeUsage(simpleP.Property); } } result = GetNewType(result); PlanCompiler.Assert(null != result, "unrecognized property type?"); return result; }