Example #1
0
        private static DbExpression WithRelationshipsClauseAsCqt(
            DbExpression row, DbExpression slotValueExpr, IEnumerable <WithRelationship> withRelationships, ProjectedSlot slot)
        {
            var relatedEntityRefs = new List <DbRelatedEntityRef>();

            WithRelationshipsClauseAsCql(
                // emitWithRelationship action
                (withRelationship) => { relatedEntityRefs.Add(withRelationship.AsCqt(row)); },
                withRelationships,
                slot);

            if (relatedEntityRefs.Count > 0)
            {
                var typeConstructor = slotValueExpr as DbNewInstanceExpression;
                Debug.Assert(
                    typeConstructor != null && typeConstructor.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType,
                    "WITH RELATIONSHIP clauses should be specified for entity type constructors only.");
                return(DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression(
                           (EntityType)typeConstructor.ResultType.EdmType,
                           typeConstructor.Arguments,
                           relatedEntityRefs));
            }
            else
            {
                return(slotValueExpr);
            }
        }
        private static DbExpression WithRelationshipsClauseAsCqt(
            DbExpression row,
            DbExpression slotValueExpr,
            IEnumerable <WithRelationship> withRelationships,
            ProjectedSlot slot)
        {
            List <DbRelatedEntityRef> relatedEntityRefs = new List <DbRelatedEntityRef>();

            CaseStatement.WithRelationshipsClauseAsCql((Action <WithRelationship>)(withRelationship => relatedEntityRefs.Add(withRelationship.AsCqt(row))), withRelationships, slot);
            if (relatedEntityRefs.Count <= 0)
            {
                return(slotValueExpr);
            }
            DbNewInstanceExpression instanceExpression = slotValueExpr as DbNewInstanceExpression;

            return((DbExpression)DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression((EntityType)instanceExpression.ResultType.EdmType, instanceExpression.Arguments, (IList <DbRelatedEntityRef>)relatedEntityRefs));
        }
Example #3
0
        private DbExpression AddFkRelatedEntityRefs(DbExpression viewConstructor)
        {
            // If the extent being simplified is not a C-Space entity set, or if it has already
            // been processed by the simplifier, then keep the original expression by returning
            // null.
            //
            if (doNotProcess)
            {
                return(null);
            }

            if (extent.BuiltInTypeKind != BuiltInTypeKind.EntitySet
                ||
                extent.EntityContainer.DataSpace != DataSpace.CSpace)
            {
                doNotProcess = true;
                return(null);
            }

            // Get a reference to the entity set being simplified, and find all the foreign key
            // (foreign key) associations for which the association set references that entity set,
            // with either association end.
            //
            var targetSet = (EntitySet)extent;
            var relSets   =
                targetSet.EntityContainer.BaseEntitySets
                .Where(es => es.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
                .Cast <AssociationSet>()
                .Where(
                    assocSet =>
                    assocSet.ElementType.IsForeignKey &&
                    assocSet.AssociationSetEnds.Any(se => se.EntitySet == targetSet)
                    )
                .ToList();

            // If no foreign key association sets that reference the entity set are present, then
            // no further processing is necessary, because FK-based related entity references cannot
            // be computed and added to the entities constructed for the entity set.
            if (relSets.Count == 0)
            {
                doNotProcess = true;
                return(null);
            }

            // For every relationship set that references this entity set, the relationship type and
            // foreign key constraint are used to determine if the entity set is the dependent set.
            // If it is the dependent set, then it is possible to augment the view definition with a
            // related entity ref that represents the navigation of the relationship set's relationship
            // from the dependent end (this entity set) to the the principal end (the entity set that
            // is referenced by the other association set end of the relationship set).
            //
            var principalSetsAndDependentTypes = new HashSet <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> >();

            foreach (var relSet in relSets)
            {
                // Retrieve the single referential constraint from the foreign key association, and
                // use it to determine whether the association set end that represents the dependent
                // end of the association references this entity set.
                //
                var fkConstraint    = relSet.ElementType.ReferentialConstraints[0];
                var dependentSetEnd = relSet.AssociationSetEnds[fkConstraint.ToRole.Name];

                if (dependentSetEnd.EntitySet == targetSet)
                {
                    var requiredSourceNavType =
                        (EntityType)TypeHelpers.GetEdmType <RefType>(dependentSetEnd.CorrespondingAssociationEndMember.TypeUsage).ElementType;
                    var principalSetEnd = relSet.AssociationSetEnds[fkConstraint.FromRole.Name];

                    // Record the entity type that an element of this dependent entity set must have in order
                    // to be a valid navigation source for the relationship set's relationship, along with the
                    // association set end for the destination (principal) end of the navigation and the FK
                    // constraint that is associated with the relationship type. This information may be used
                    // later to construct a related entity ref for any entity constructor expression in the view
                    // that produces an entity of the required source type or a subtype.
                    //
                    principalSetsAndDependentTypes.Add(Tuple.Create(requiredSourceNavType, principalSetEnd, fkConstraint));
                }
            }

            // If no foreign key association sets that use the entity set as the dependent set are present,
            // then no further processing is possible, since FK-based related entity refs can only be added
            // to the view definition for navigations from the dependent end of the relationship to the principal.
            //
            if (principalSetsAndDependentTypes.Count == 0)
            {
                doNotProcess = true;
                return(null);
            }

            // This rule supports a view that is capped with a projection of the form
            // (input).Project(x => new Entity())
            // or
            // (input).Project(x => CASE WHEN (condition1) THEN new Entity1() ELSE WHEN (condition2) THEN new Entity2()... ELSE new EntityN())
            // where every new instance expression Entity1()...EntityN() constructs an entity of a type
            // that is compatible with the entity set's element type.
            // Here, the list of all DbNewInstanceExpressions contained in the projection is remembered,
            // along with any CASE statement conditions, if present. These expressions will be updated
            // if necessary and used to build a new capping projection if any of the entity constructors
            // are augmented with FK-based related entity references.
            //
            var entityProject = (DbProjectExpression)viewConstructor;
            var constructors  = new List <DbNewInstanceExpression>();
            List <DbExpression> conditions = null;

            if (entityProject.Projection.ExpressionKind
                == DbExpressionKind.Case)
            {
                // If the projection is a DbCaseExpression, then every result must be a DbNewInstanceExpression
                var discriminatedConstructor = (DbCaseExpression)entityProject.Projection;
                conditions = new List <DbExpression>(discriminatedConstructor.When.Count);
                for (var idx = 0; idx < discriminatedConstructor.When.Count; idx++)
                {
                    conditions.Add(discriminatedConstructor.When[idx]);
                    constructors.Add((DbNewInstanceExpression)discriminatedConstructor.Then[idx]);
                }
                constructors.Add((DbNewInstanceExpression)discriminatedConstructor.Else);
            }
            else
            {
                // Otherwise, the projection must be a single DbNewInstanceExpression
                constructors.Add((DbNewInstanceExpression)entityProject.Projection);
            }

            var rebuildView = false;

            for (var idx = 0; idx < constructors.Count; idx++)
            {
                var entityConstructor     = constructors[idx];
                var constructedEntityType = TypeHelpers.GetEdmType <EntityType>(entityConstructor.ResultType);

                var relatedRefs =
                    principalSetsAndDependentTypes
                    .Where(psdt => constructedEntityType == psdt.Item1 || constructedEntityType.IsSubtypeOf(psdt.Item1))
                    .Select(
                        psdt => RelatedEntityRefFromAssociationSetEnd(constructedEntityType, entityConstructor, psdt.Item2, psdt.Item3))
                    .ToList();

                if (relatedRefs.Count > 0)
                {
                    if (entityConstructor.HasRelatedEntityReferences)
                    {
                        relatedRefs = entityConstructor.RelatedEntityReferences.Concat(relatedRefs).ToList();
                    }

                    entityConstructor = DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression(
                        constructedEntityType, entityConstructor.Arguments, relatedRefs);
                    constructors[idx] = entityConstructor;
                    rebuildView       = true;
                }
            }

            // Default to returning null to indicate that this rule did not produce a modified expression
            //
            DbExpression result = null;

            if (rebuildView)
            {
                // rebuildView is true, so entity constructing DbNewInstanceExpression(s) were encountered
                // and updated with additional related entity refs. The DbProjectExpression that caps the
                // view definition therefore needs to be rebuilt and returned as the result of this rule.
                //
                if (conditions != null)
                {
                    // The original view definition projection was a DbCaseExpression.
                    // The new expression is also a DbCaseExpression that uses the conditions from the
                    // original expression together with the updated result expressions to produce the
                    // new capping projection.
                    //
                    var whens = new List <DbExpression>(conditions.Count);
                    var thens = new List <DbExpression>(conditions.Count);
                    for (var idx = 0; idx < conditions.Count; idx++)
                    {
                        whens.Add(conditions[idx]);
                        thens.Add(constructors[idx]);
                    }

                    result = entityProject.Input.Project(DbExpressionBuilder.Case(whens, thens, constructors[conditions.Count]));
                }
                else
                {
                    // Otherwise, the capping projection consists entirely of the updated DbNewInstanceExpression.
                    //
                    result = entityProject.Input.Project(constructors[0]);
                }
            }

            // Regardless of whether or not the view was updated, this rule should not be applied again during rule processing
            doNotProcess = true;
            return(result);
        }
Example #4
0
        private DbExpression AddFkRelatedEntityRefs(DbExpression viewConstructor)
        {
            if (this.doNotProcess)
            {
                return((DbExpression)null);
            }
            if (this.extent.BuiltInTypeKind != BuiltInTypeKind.EntitySet || this.extent.EntityContainer.DataSpace != DataSpace.CSpace)
            {
                this.doNotProcess = true;
                return((DbExpression)null);
            }
            EntitySet             targetSet = (EntitySet)this.extent;
            List <AssociationSet> list1     = targetSet.EntityContainer.BaseEntitySets.Where <EntitySetBase>((Func <EntitySetBase, bool>)(es => es.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)).Cast <AssociationSet>().Where <AssociationSet>((Func <AssociationSet, bool>)(assocSet =>
            {
                if (assocSet.ElementType.IsForeignKey)
                {
                    return(assocSet.AssociationSetEnds.Any <AssociationSetEnd>((Func <AssociationSetEnd, bool>)(se => se.EntitySet == targetSet)));
                }
                return(false);
            })).ToList <AssociationSet>();

            if (list1.Count == 0)
            {
                this.doNotProcess = true;
                return((DbExpression)null);
            }
            HashSet <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> > source = new HashSet <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> >();

            foreach (AssociationSet associationSet in list1)
            {
                ReferentialConstraint referentialConstraint = associationSet.ElementType.ReferentialConstraints[0];
                AssociationSetEnd     associationSetEnd1    = associationSet.AssociationSetEnds[referentialConstraint.ToRole.Name];
                if (associationSetEnd1.EntitySet == targetSet)
                {
                    EntityType        elementType        = (EntityType)TypeHelpers.GetEdmType <RefType>(associationSetEnd1.CorrespondingAssociationEndMember.TypeUsage).ElementType;
                    AssociationSetEnd associationSetEnd2 = associationSet.AssociationSetEnds[referentialConstraint.FromRole.Name];
                    source.Add(Tuple.Create <EntityType, AssociationSetEnd, ReferentialConstraint>(elementType, associationSetEnd2, referentialConstraint));
                }
            }
            if (source.Count == 0)
            {
                this.doNotProcess = true;
                return((DbExpression)null);
            }
            DbProjectExpression            projectExpression      = (DbProjectExpression)viewConstructor;
            List <DbNewInstanceExpression> instanceExpressionList = new List <DbNewInstanceExpression>();
            List <DbExpression>            dbExpressionList1      = (List <DbExpression>)null;

            if (projectExpression.Projection.ExpressionKind == DbExpressionKind.Case)
            {
                DbCaseExpression projection = (DbCaseExpression)projectExpression.Projection;
                dbExpressionList1 = new List <DbExpression>(projection.When.Count);
                for (int index = 0; index < projection.When.Count; ++index)
                {
                    dbExpressionList1.Add(projection.When[index]);
                    instanceExpressionList.Add((DbNewInstanceExpression)projection.Then[index]);
                }
                instanceExpressionList.Add((DbNewInstanceExpression)projection.Else);
            }
            else
            {
                instanceExpressionList.Add((DbNewInstanceExpression)projectExpression.Projection);
            }
            bool flag = false;

            for (int index = 0; index < instanceExpressionList.Count; ++index)
            {
                DbNewInstanceExpression entityConstructor = instanceExpressionList[index];
                EntityType constructedEntityType          = TypeHelpers.GetEdmType <EntityType>(entityConstructor.ResultType);
                List <DbRelatedEntityRef> list2           = source.Where <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint> >((Func <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint>, bool>)(psdt =>
                {
                    if (constructedEntityType != psdt.Item1)
                    {
                        return(constructedEntityType.IsSubtypeOf((EdmType)psdt.Item1));
                    }
                    return(true);
                })).Select <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint>, DbRelatedEntityRef>((Func <Tuple <EntityType, AssociationSetEnd, ReferentialConstraint>, DbRelatedEntityRef>)(psdt => ViewSimplifier.RelatedEntityRefFromAssociationSetEnd(constructedEntityType, entityConstructor, psdt.Item2, psdt.Item3))).ToList <DbRelatedEntityRef>();
                if (list2.Count > 0)
                {
                    if (entityConstructor.HasRelatedEntityReferences)
                    {
                        list2 = entityConstructor.RelatedEntityReferences.Concat <DbRelatedEntityRef>((IEnumerable <DbRelatedEntityRef>)list2).ToList <DbRelatedEntityRef>();
                    }
                    entityConstructor             = DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression(constructedEntityType, entityConstructor.Arguments, (IList <DbRelatedEntityRef>)list2);
                    instanceExpressionList[index] = entityConstructor;
                    flag = true;
                }
            }
            DbExpression dbExpression = (DbExpression)null;

            if (flag)
            {
                if (dbExpressionList1 != null)
                {
                    List <DbExpression> dbExpressionList2 = new List <DbExpression>(dbExpressionList1.Count);
                    List <DbExpression> dbExpressionList3 = new List <DbExpression>(dbExpressionList1.Count);
                    for (int index = 0; index < dbExpressionList1.Count; ++index)
                    {
                        dbExpressionList2.Add(dbExpressionList1[index]);
                        dbExpressionList3.Add((DbExpression)instanceExpressionList[index]);
                    }
                    dbExpression = (DbExpression)projectExpression.Input.Project((DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>)dbExpressionList2, (IEnumerable <DbExpression>)dbExpressionList3, (DbExpression)instanceExpressionList[dbExpressionList1.Count]));
                }
                else
                {
                    dbExpression = (DbExpression)projectExpression.Input.Project((DbExpression)instanceExpressionList[0]);
                }
            }
            this.doNotProcess = true;
            return(dbExpression);
        }