// <summary> // Add the rel property induced by the specified relationship, (if the target // end has a multiplicity of one) // We only keep track of rel-properties that are "interesting" // </summary> // <param name="associationType"> the association relationship </param> // <param name="fromEnd"> source end of the relationship traversal </param> // <param name="toEnd"> target end of the traversal </param> private void AddRelProperty( AssociationType associationType, AssociationEndMember fromEnd, AssociationEndMember toEnd) { if (toEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { return; } var prop = new RelProperty(associationType, fromEnd, toEnd); if (_interestingRelProperties == null || !_interestingRelProperties.Contains(prop)) { return; } var entityType = ((RefType)fromEnd.TypeUsage.EdmType).ElementType; List <RelProperty> propList; if (!_relPropertyMap.TryGetValue(entityType, out propList)) { propList = new List <RelProperty>(); _relPropertyMap[entityType] = propList; } propList.Add(prop); }
private void AddRelProperty( AssociationType associationType, AssociationEndMember fromEnd, AssociationEndMember toEnd) { if (toEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { return; } RelProperty relProperty = new RelProperty((RelationshipType)associationType, (RelationshipEndMember)fromEnd, (RelationshipEndMember)toEnd); if (this._interestingRelProperties == null || !this._interestingRelProperties.Contains(relProperty)) { return; } EntityTypeBase elementType = ((RefType)fromEnd.TypeUsage.EdmType).ElementType; List <RelProperty> relPropertyList; if (!this._relPropertyMap.TryGetValue(elementType, out relPropertyList)) { relPropertyList = new List <RelProperty>(); this._relPropertyMap[elementType] = relPropertyList; } relPropertyList.Add(relProperty); }
// <summary> // Add the rel property induced by the specified relationship, (if the target // end has a multiplicity of one) // We only keep track of rel-properties that are "interesting" // </summary> // <param name="associationType"> the association relationship </param> // <param name="fromEnd"> source end of the relationship traversal </param> // <param name="toEnd"> target end of the traversal </param> private void AddRelProperty( AssociationType associationType, AssociationEndMember fromEnd, AssociationEndMember toEnd) { if (toEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { return; } var prop = new RelProperty(associationType, fromEnd, toEnd); if (_interestingRelProperties == null || !_interestingRelProperties.Contains(prop)) { return; } var entityType = ((RefType)fromEnd.TypeUsage.EdmType).ElementType; List<RelProperty> propList; if (!_relPropertyMap.TryGetValue(entityType, out propList)) { propList = new List<RelProperty>(); _relPropertyMap[entityType] = propList; } propList.Add(prop); }
private void AddRelPropertyReference(RelProperty relProperty) { if (relProperty.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many || this.m_referencedRelProperties.Contains(relProperty)) { return; } this.m_referencedRelProperties.Add(relProperty); }
public override bool Equals(object obj) { RelProperty relProperty = obj as RelProperty; if (relProperty != null && this.Relationship.EdmEquals((MetadataItem)relProperty.Relationship) && this.FromEnd.EdmEquals((MetadataItem)relProperty.FromEnd)) { return(this.ToEnd.EdmEquals((MetadataItem)relProperty.ToEnd)); } return(false); }
/// <summary> /// Creates a nested property ref for a rel-property. Delegates to the function above /// </summary> /// <param name="p"> the rel-property </param> /// <returns> a nested property ref </returns> internal PropertyRef CreateNestedPropertyRef(RelProperty p) { return CreateNestedPropertyRef(new RelPropertyRef(p)); }
// <summary> // Simple constructor // </summary> // <param name="property"> the property metadata </param> internal RelPropertyRef(RelProperty property) { m_property = property; }
internal NavigateOp(TypeUsage type, RelProperty relProperty) : base(OpType.Navigate, type) { m_property = relProperty; }
private static bool TryMatchEntityTypeConstructor( DbExpression then, Dictionary<EdmProperty, DbExpression> propertyMap, Dictionary<RelProperty, DbExpression> relPropertyMap, Dictionary<EntityType, List<RelProperty>> typeToRelPropertyMap, out EntityType entityType) { if (then.ExpressionKind != DbExpressionKind.NewInstance) { entityType = null; return false; } var constructor = (DbNewInstanceExpression)then; entityType = (EntityType)constructor.ResultType.EdmType; // process arguments to constructor (must be aligned across all case statements) Debug.Assert(entityType.Properties.Count == constructor.Arguments.Count, "invalid new instance"); for (var j = 0; j < entityType.Properties.Count; j++) { var property = entityType.Properties[j]; var assignment = constructor.Arguments[j]; DbExpression existingAssignment; if (propertyMap.TryGetValue(property, out existingAssignment)) { if (!ExpressionsCompatible(assignment, existingAssignment)) { return false; } } else { propertyMap.Add(property, assignment); } } // Now handle the rel properties if (constructor.HasRelatedEntityReferences) { List<RelProperty> relPropertyList; if (!typeToRelPropertyMap.TryGetValue(entityType, out relPropertyList)) { relPropertyList = new List<RelProperty>(); typeToRelPropertyMap[entityType] = relPropertyList; } foreach (var relatedRef in constructor.RelatedEntityReferences) { var relProperty = new RelProperty( (RelationshipType)relatedRef.TargetEnd.DeclaringType, relatedRef.SourceEnd, relatedRef.TargetEnd); var assignment = relatedRef.TargetEntityReference; DbExpression existingAssignment; if (relPropertyMap.TryGetValue(relProperty, out existingAssignment)) { if (!ExpressionsCompatible(assignment, existingAssignment)) { return false; } } else { relPropertyMap.Add(relProperty, assignment); } relPropertyList.Add(relProperty); } } return true; }
private Node RewriteManyToManyNavigationProperty( RelProperty relProperty, List<RelationshipSet> relationshipSets, Node sourceRefNode) { PlanCompiler.Assert(relationshipSets.Count > 0, "expected at least one relationship set here"); PlanCompiler.Assert( relProperty.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many && relProperty.FromEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many, "Expected target end multiplicity to be 'many'. Found " + relProperty + "; multiplicity = " + relProperty.ToEnd.RelationshipMultiplicity); Node ret = null; var joinNodes = new List<Node>(relationshipSets.Count); var outputVars = new List<Var>(relationshipSets.Count * 2); foreach (var r in relationshipSets) { Var rsVar; Var esVar; var joinNode = BuildJoinForNavProperty(r, relProperty.ToEnd, out rsVar, out esVar); joinNodes.Add(joinNode); outputVars.Add(rsVar); outputVars.Add(esVar); } // // Build the union-all node // Node unionAllNode; IList<Var> unionAllVars; m_command.BuildUnionAllLadder(joinNodes, outputVars, out unionAllNode, out unionAllVars); // // Now build out the filterOp over the left-side var // var rsSourceRefNode = m_command.CreateNode( m_command.CreatePropertyOp(relProperty.FromEnd), m_command.CreateNode(m_command.CreateVarRefOp(unionAllVars[0]))); var predicate = m_command.BuildComparison( OpType.EQ, sourceRefNode, rsSourceRefNode); var filterNode = m_command.CreateNode( m_command.CreateFilterOp(), unionAllNode, predicate); // // Finally, build out a project node that only projects out the entity side // var projectNode = m_command.BuildProject(filterNode, new[] { unionAllVars[1] }, new Node[] { }); // // Build a collectOp over the project node // ret = m_command.BuildCollect(projectNode, unionAllVars[1]); return ret; }
// <summary> // Create a new NavigateOp node // </summary> // <param name="type"> the output type of the navigateOp </param> // <param name="relProperty"> the relationship property </param> // <returns> the navigateOp </returns> internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty) { // keep track of rel-properties AddRelPropertyReference(relProperty); return new NavigateOp(type, relProperty); }
/// <summary> /// Rewrite a navigation property when the target end has multiplicity /// of one (or zero..one) and the source end has multiplicity of many. /// /// Note that this translation is also valid for a navigation property when the target /// end has multiplicity of one (or zero..one) and the source end has multiplicity of one /// (or zero..one), but a different translation is used because it yields a simpler query in some cases. /// /// We simply pick up the corresponding rel property from the input entity, and /// apply a deref operation /// NavProperty(e, n) => deref(relproperty(e, r)) /// where e is the entity expression, n is the nav-property, and r is the corresponding /// rel-property /// </summary> /// <param name="relProperty">the rel-property describing the navigation</param> /// <param name="sourceEntityNode">entity instance that we're starting the traversal from</param> /// <param name="resultType">type of the target entity</param> /// <returns>a rewritten subtree</returns> private Node RewriteManyToOneNavigationProperty( RelProperty relProperty, Node sourceEntityNode, TypeUsage resultType) { var relPropertyOp = m_command.CreateRelPropertyOp(relProperty); var relPropertyNode = m_command.CreateNode(relPropertyOp, sourceEntityNode); var derefOp = m_command.CreateDerefOp(resultType); var derefNode = m_command.CreateNode(derefOp, relPropertyNode); return derefNode; }
/// <summary> /// Rewrite a navigation property when the target end has multiplicity /// of one (or zero..one) and the source end has multiplicity of one (or zero..one). /// /// <see cref="RewriteFromOneNavigationProperty"/> /// We add the translation as a subquery to the parent rel op and return a reference to /// the corresponding var /// </summary> /// <param name="relProperty">the rel-property describing the relationship traversal</param> /// <param name="relationshipSets">the list of relevant relationshipsets</param> /// <param name="sourceRefNode">node tree corresponding to the source entity ref</param> /// <returns>the rewritten subtree</returns> private Node RewriteOneToOneNavigationProperty( RelProperty relProperty, List<RelationshipSet> relationshipSets, Node sourceRefNode) { Var outputVar; var ret = RewriteFromOneNavigationProperty(relProperty, relationshipSets, sourceRefNode, out outputVar); ret = VisitNode(ret); ret = AddSubqueryToParentRelOp(outputVar, ret); return ret; }
/// <summary> /// Find the relationshipset that matches the current entityset + from/to roles /// </summary> /// <param name="entitySet"></param> /// <param name="relProperty"></param> /// <returns></returns> private static RelationshipSet FindRelationshipSet(EntitySetBase entitySet, RelProperty relProperty) { foreach (var es in entitySet.EntityContainer.BaseEntitySets) { var rs = es as AssociationSet; if (rs != null && rs.ElementType.EdmEquals(relProperty.Relationship) && rs.AssociationSetEnds[relProperty.FromEnd.Identity].EntitySet.EdmEquals(entitySet)) { return rs; } } return null; }
// <summary> // Create a "relationship" propertyOp // </summary> // <param name="prop"> the relationship property </param> // <returns> a RelPropertyOp </returns> internal RelPropertyOp CreateRelPropertyOp(RelProperty prop) { AddRelPropertyReference(prop); return new RelPropertyOp(prop.ToEnd.TypeUsage, prop); }
// <summary> // Creates a new PropertyOp // </summary> // <param name="prop"> EdmProperty metadata that specifies the property </param> // <returns> A new PropertyOp that references the specified property metadata </returns> internal PropertyOp CreatePropertyOp(EdmMember prop) { // // Track all rel-properties // var navProp = prop as NavigationProperty; if (navProp != null) { var relProperty = new RelProperty(navProp.RelationshipType, navProp.FromEndMember, navProp.ToEndMember); AddRelPropertyReference(relProperty); var inverseRelProperty = new RelProperty(navProp.RelationshipType, navProp.ToEndMember, navProp.FromEndMember); AddRelPropertyReference(inverseRelProperty); } // Actually create the propertyOp return new PropertyOp(Helper.GetModelTypeUsage(prop), prop); }
// <summary> // Is this rel-property referenced in the query so far // </summary> // <param name="relProperty"> the rel-property </param> // <returns> true, if the rel property was referenced in the query </returns> internal virtual bool IsRelPropertyReferenced(RelProperty relProperty) { var ret = m_referencedRelProperties.Contains(relProperty); return ret; }
// <summary> // Mark this rel-property as "referenced" in the current query, if the target // end has multiplicity of one (or zero_or_one) // </summary> // <param name="relProperty"> the rel-property </param> private void AddRelPropertyReference(RelProperty relProperty) { if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many && !m_referencedRelProperties.Contains(relProperty)) { m_referencedRelProperties.Add(relProperty); } }
private Node BuildRelPropertyExpression( EntitySetBase entitySet, RelProperty relProperty, Node keyExpr) { // // Make a copy of the current key expression // keyExpr = OpCopier.Copy(m_command, keyExpr); // // Find the relationship set corresponding to this entityset (and relProperty) // Return a null ref, if we can't find one // var relSet = FindRelationshipSet(entitySet, relProperty); if (relSet == null) { return m_command.CreateNode(m_command.CreateNullOp(relProperty.ToEnd.TypeUsage)); } var scanTableOp = m_command.CreateScanTableOp(Command.CreateTableDefinition(relSet)); PlanCompiler.Assert( scanTableOp.Table.Columns.Count == 1, "Unexpected column count for table:" + scanTableOp.Table.TableMetadata.Extent + "=" + scanTableOp.Table.Columns.Count); var scanTableVar = scanTableOp.Table.Columns[0]; var scanNode = m_command.CreateNode(scanTableOp); var sourceEndNode = m_command.CreateNode( m_command.CreatePropertyOp(relProperty.FromEnd), m_command.CreateNode(m_command.CreateVarRefOp(scanTableVar))); var predicateNode = m_command.BuildComparison( OpType.EQ, keyExpr, m_command.CreateNode(m_command.CreateGetRefKeyOp(keyExpr.Op.Type), sourceEndNode)); var filterNode = m_command.CreateNode( m_command.CreateFilterOp(), scanNode, predicateNode); // // Process the node, and then add this as a subquery to the parent relop // var ret = VisitNode(filterNode); ret = AddSubqueryToParentRelOp(scanTableVar, ret); // // Now extract out the target end property // ret = m_command.CreateNode( m_command.CreatePropertyOp(relProperty.ToEnd), ret); return ret; }
internal virtual bool IsRelPropertyReferenced(RelProperty relProperty) { return(this.m_referencedRelProperties.Contains(relProperty)); }
/// <summary> /// Rewrite a navigation property when the source end has multiplicity /// of one (or zero..one) and the target end has multiplicity of many. /// /// <see cref="RewriteFromOneNavigationProperty"/> /// We also build out a CollectOp over the subquery above, and return that /// </summary> /// <param name="relProperty">the rel-property describing the relationship traversal</param> /// <param name="relationshipSets">the list of relevant relationshipsets</param> /// <param name="sourceRefNode">node tree corresponding to the source entity ref</param> /// <returns>the rewritten subtree</returns> private Node RewriteOneToManyNavigationProperty( RelProperty relProperty, List<RelationshipSet> relationshipSets, Node sourceRefNode) { Var outputVar; var ret = RewriteFromOneNavigationProperty(relProperty, relationshipSets, sourceRefNode, out outputVar); // The return value is a collection, but used as a property, thus it needs to be capped with a collect ret = m_command.BuildCollect(ret, outputVar); return ret; }
internal RelPropertyOp CreateRelPropertyOp(RelProperty prop) { this.AddRelPropertyReference(prop); return(new RelPropertyOp(prop.ToEnd.TypeUsage, prop)); }
private Node RewriteFromOneNavigationProperty( RelProperty relProperty, List<RelationshipSet> relationshipSets, Node sourceRefNode, out Var outputVar) { PlanCompiler.Assert(relationshipSets.Count > 0, "expected at least one relationship set here"); PlanCompiler.Assert( relProperty.FromEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many, "Expected source end multiplicity to be one. Found 'Many' instead " + relProperty); var entityType = TypeHelpers.GetElementTypeUsage(relProperty.ToEnd.TypeUsage); var scanTableNodes = new List<Node>(relationshipSets.Count); var scanTableVars = new List<Var>(relationshipSets.Count); foreach (var r in relationshipSets) { var entitySet = FindTargetEntitySet(r, relProperty.ToEnd); Var tableVar; var tableNode = BuildOfTypeTable(entitySet, entityType, out tableVar); scanTableNodes.Add(tableNode); scanTableVars.Add(tableVar); } // // Build the union-all node // Node unionAllNode; m_command.BuildUnionAllLadder(scanTableNodes, scanTableVars, out unionAllNode, out outputVar); // // Now build up the appropriate filter. Select out the relproperty from the other end // var inverseRelProperty = new RelProperty(relProperty.Relationship, relProperty.ToEnd, relProperty.FromEnd); PlanCompiler.Assert( m_command.IsRelPropertyReferenced(inverseRelProperty), "Unreferenced rel property? " + inverseRelProperty); var inverseRelPropertyNode = m_command.CreateNode( m_command.CreateRelPropertyOp(inverseRelProperty), m_command.CreateNode(m_command.CreateVarRefOp(outputVar))); var predicateNode = m_command.BuildComparison( OpType.EQ, sourceRefNode, inverseRelPropertyNode); var ret = m_command.CreateNode(m_command.CreateFilterOp(), unionAllNode, predicateNode); return ret; }
internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty) { this.AddRelPropertyReference(relProperty); return(new NavigateOp(type, relProperty)); }
private Node RewriteNavigationProperty( NavigationProperty navProperty, Node sourceEntityNode, TypeUsage resultType) { var relProperty = new RelProperty(navProperty.RelationshipType, navProperty.FromEndMember, navProperty.ToEndMember); PlanCompiler.Assert( m_command.IsRelPropertyReferenced(relProperty) || (relProperty.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many), "Unreferenced rel property? " + relProperty); // Handle N:1 if ((relProperty.FromEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) && (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many)) { return RewriteManyToOneNavigationProperty(relProperty, sourceEntityNode, resultType); } // // Find the list of all relationships that could satisfy this relationship // If we find no matching relationship set, simply return a null node / empty collection // var relationshipSets = GetRelationshipSets(relProperty.Relationship); if (relationshipSets.Count == 0) { // return an empty set / null node if (relProperty.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { return m_command.CreateNode(m_command.CreateNewMultisetOp(resultType)); } return m_command.CreateNode(m_command.CreateNullOp(resultType)); } // Build out a ref over the source entity var sourceRefNode = m_command.CreateNode( m_command.CreateGetEntityRefOp(relProperty.FromEnd.TypeUsage), sourceEntityNode); // Hanlde the 1:M and N:M cases if (relProperty.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { // Handle N:M if (relProperty.FromEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { return RewriteManyToManyNavigationProperty(relProperty, relationshipSets, sourceRefNode); } // Handle 1:M return RewriteOneToManyNavigationProperty(relProperty, relationshipSets, sourceRefNode); } // Handle 1:1 return RewriteOneToOneNavigationProperty(relProperty, relationshipSets, sourceRefNode); }
internal RelPropertyOp(TypeUsage type, RelProperty property) : base(OpType.RelProperty, type) { m_property = property; }