/// <summary> /// Overrides the default equality function. Two SimplePropertyRefs are /// equal, if they describe the same property /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { SimplePropertyRef other = obj as SimplePropertyRef; return(other != null && InternalTrees.Command.EqualTypes(m_property.DeclaringType, other.m_property.DeclaringType) && other.m_property.Name.Equals(this.m_property.Name)); }
/// <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); }
/// <summary> /// Gets the list of key properties for an entity /// </summary> /// <param name="entityType"></param> /// <returns></returns> private static PropertyRefList GetKeyProperties(md.EntityType entityType) { PropertyRefList desiredProperties = new PropertyRefList(); foreach (md.EdmMember p in entityType.KeyMembers) { md.EdmProperty edmP = p as md.EdmProperty; PlanCompiler.Assert(edmP != null, "EntityType had non-EdmProperty key member?"); SimplePropertyRef pRef = new SimplePropertyRef(edmP); desiredProperties.Add(pRef); } return(desiredProperties); }
/// <summary> /// Get the list of "key" properties (in the flattened type) /// </summary> /// <returns>the key property equivalents in the flattened type</returns> internal IEnumerable <PropertyRef> GetKeyPropertyRefs() { md.EntityTypeBase entityType = null; md.RefType refType = null; if (TypeHelpers.TryGetEdmType <md.RefType>(m_type, out refType)) { entityType = refType.ElementType; } else { entityType = TypeHelpers.GetEdmType <md.EntityTypeBase>(m_type); } // Walk through the list of keys of the entity type, and find their analogs in the // "flattened" type foreach (md.EdmMember p in entityType.KeyMembers) { // Eventually this could be RelationshipEndMember, but currently only properties are suppported as key members PlanCompiler.Assert(p is md.EdmProperty, "Non-EdmProperty key members are not supported"); SimplePropertyRef spr = new SimplePropertyRef(p); yield return(spr); } }
/// <summary> /// Flattens out a constructor into a "flat" record constructor. /// The "flat" record type is looked up for the current constructor's type, /// and each property is filled out from the current constructor's fields /// </summary> /// <param name="op">The NewRecordOp/NewInstanceOp</param> /// <param name="n">The current subtree</param> /// <returns>the new subtree</returns> private Node FlattenConstructor(ScalarOp op, Node n) { PlanCompiler.Assert(op.OpType == OpType.NewInstance || op.OpType == OpType.NewRecord || op.OpType == OpType.DiscriminatedNewEntity || op.OpType == OpType.NewEntity, "unexpected op: " + op.OpType + "?"); // First visit all my children VisitChildren(n); // Find the new type corresponding to the type TypeInfo typeInfo = m_typeInfo.GetTypeInfo(op.Type); md.RowType flatType = typeInfo.FlattenedType; NewEntityBaseOp newEntityOp = op as NewEntityBaseOp; // Identify the fields IEnumerable opFields = null; DiscriminatedNewEntityOp discriminatedNewInstanceOp = null; if (op.OpType == OpType.NewRecord) { // Get only those fields that I have values for opFields = ((NewRecordOp)op).Properties; } else if (op.OpType == OpType.DiscriminatedNewEntity) { // Get all properties projected by the discriminated new instance op discriminatedNewInstanceOp = (DiscriminatedNewEntityOp)op; opFields = discriminatedNewInstanceOp.DiscriminatorMap.Properties; } else { // Children align with structural members of type for a standard NewInstanceOp opFields = TypeHelpers.GetAllStructuralMembers(op.Type); } // Next, walk through each of my field, and flatten out any field // that is structured. List<md.EdmProperty> newFields = new List<md.EdmProperty>(); List<Node> newFieldValues = new List<Node>(); // // NOTE: we expect the type id property and the entityset id properties // to be at the start of the properties collection. // // Add a typeid property if we need one // if (typeInfo.HasTypeIdProperty) { newFields.Add(typeInfo.TypeIdProperty); if (null == discriminatedNewInstanceOp) { newFieldValues.Add(CreateTypeIdConstant(typeInfo)); } else { // first child in DiscriminatedNewInstanceOp is discriminator/typeid Node discriminator = n.Children[0]; if (null == typeInfo.RootType.DiscriminatorMap) { // if there are multiple sets (or free-floating constructors) for this type // hierarchy, normalize the discriminator value to expose the standard // '0X' style values discriminator = NormalizeTypeDiscriminatorValues(discriminatedNewInstanceOp, discriminator); } newFieldValues.Add(discriminator); } } // // Add an entitysetid property if we need one // if (typeInfo.HasEntitySetIdProperty) { newFields.Add(typeInfo.EntitySetIdProperty); PlanCompiler.Assert(newEntityOp != null, "unexpected optype:" + op.OpType); Node entitySetIdNode = GetEntitySetIdExpr(typeInfo.EntitySetIdProperty, newEntityOp); // Get the entity-set-id of the "current" entityset newFieldValues.Add(entitySetIdNode); } // Add a nullability property if we need one if (typeInfo.HasNullSentinelProperty) { newFields.Add(typeInfo.NullSentinelProperty); newFieldValues.Add(CreateNullSentinelConstant()); } // // first child of discriminatedNewInstanceOp is the typeId; otherwise, the first child is the first property // int childrenIndex = null == discriminatedNewInstanceOp ? 0 : 1; foreach (md.EdmMember opField in opFields) { Node fieldValue = n.Children[childrenIndex]; if (TypeUtils.IsStructuredType(md.Helper.GetModelTypeUsage(opField))) { // Flatten out nested type md.RowType nestedFlatType = m_typeInfo.GetTypeInfo(md.Helper.GetModelTypeUsage(opField)).FlattenedType; // Find offset of opField in top-level flat type int nestedPropertyOffset = typeInfo.RootType.GetNestedStructureOffset(new SimplePropertyRef(opField)); foreach (md.EdmProperty nestedProperty in nestedFlatType.Properties) { // Try to build up an accessor for this property from the input Node nestedPropertyValue = BuildAccessor(fieldValue, nestedProperty); if (null != nestedPropertyValue) { newFields.Add(flatType.Properties[nestedPropertyOffset]); newFieldValues.Add(nestedPropertyValue); } nestedPropertyOffset++; } } else { PropertyRef propRef = new SimplePropertyRef(opField); md.EdmProperty outputTypeProp = typeInfo.GetNewProperty(propRef); newFields.Add(outputTypeProp); newFieldValues.Add(fieldValue); } childrenIndex++; } // // We've now handled all the regular properties. Now, walk through all the rel properties - // obviously, this only applies for the *NewEntityOps // if (newEntityOp != null) { foreach (RelProperty relProp in newEntityOp.RelationshipProperties) { Node fieldValue = n.Children[childrenIndex]; md.RowType nestedFlatType = m_typeInfo.GetTypeInfo(relProp.ToEnd.TypeUsage).FlattenedType; // Find offset of opField in top-level flat type int nestedPropertyOffset = typeInfo.RootType.GetNestedStructureOffset(new RelPropertyRef(relProp)); foreach (md.EdmProperty nestedProperty in nestedFlatType.Properties) { // Try to build up an accessor for this property from the input Node nestedPropertyValue = BuildAccessor(fieldValue, nestedProperty); if (null != nestedPropertyValue) { newFields.Add(flatType.Properties[nestedPropertyOffset]); newFieldValues.Add(nestedPropertyValue); } nestedPropertyOffset++; } childrenIndex++; } } // // So, now we have the list of all fields that should make up the // flat type. Create a new node with them. // NewRecordOp newOp = m_command.CreateNewRecordOp(typeInfo.FlattenedTypeUsage, newFields); Node newNode = m_command.CreateNode(newOp, newFieldValues); return newNode; }
/// <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 list of "key" properties (in the flattened type) /// </summary> /// <returns>the key property equivalents in the flattened type</returns> internal IEnumerable<PropertyRef> GetKeyPropertyRefs() { md.EntityTypeBase entityType = null; md.RefType refType = null; if (TypeHelpers.TryGetEdmType<md.RefType>(m_type, out refType)) { entityType = refType.ElementType; } else { entityType = TypeHelpers.GetEdmType<md.EntityTypeBase>(m_type); } // Walk through the list of keys of the entity type, and find their analogs in the // "flattened" type foreach (md.EdmMember p in entityType.KeyMembers) { // Eventually this could be RelationshipEndMember, but currently only properties are suppported as key members PlanCompiler.Assert(p is md.EdmProperty, "Non-EdmProperty key members are not supported"); SimplePropertyRef spr = new SimplePropertyRef(p); yield return spr; } }
/// <summary> /// Gets the list of key properties for an entity /// </summary> /// <param name="entityType"></param> /// <returns></returns> private static PropertyRefList GetKeyProperties(md.EntityType entityType) { PropertyRefList desiredProperties = new PropertyRefList(); foreach (md.EdmMember p in entityType.KeyMembers) { md.EdmProperty edmP = p as md.EdmProperty; PlanCompiler.Assert(edmP != null, "EntityType had non-EdmProperty key member?"); SimplePropertyRef pRef = new SimplePropertyRef(edmP); desiredProperties.Add(pRef); } return desiredProperties; }