Beispiel #1
0
        // <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);
        }
Beispiel #4
0
 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;
 }
Beispiel #8
0
 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;
        }
Beispiel #11
0
 // <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;
 }
Beispiel #15
0
 // <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);
 }
Beispiel #16
0
        // <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);
        }
Beispiel #17
0
 // <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;
 }
Beispiel #18
0
 // <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;
        }
Beispiel #20
0
 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;
        }
Beispiel #22
0
 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;
        }
Beispiel #24
0
 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;
 }