Example #1
0
        private DbExpression GenerateScalarResultMappingView(DbExpression storeFunctionInvoke)
        {
            DbExpression queryExpression = storeFunctionInvoke;

            CollectionType functionImportReturnType;

            if (!MetadataHelper.TryGetFunctionImportReturnCollectionType(this.FunctionImport, 0, out functionImportReturnType))
            {
                Debug.Fail("Failed to get the result type of the function import.");
            }

            Debug.Assert(TypeSemantics.IsCollectionType(queryExpression.ResultType), "Store function must be TVF (collection expected).");
            var collectionType = (CollectionType)queryExpression.ResultType.EdmType;

            Debug.Assert(TypeSemantics.IsRowType(collectionType.TypeUsage), "Store function must be TVF (collection of rows expected).");
            var rowType = (RowType)collectionType.TypeUsage.EdmType;
            var column  = rowType.Properties[0];

            Func <DbExpression, DbExpression> scalarView = (DbExpression row) =>
            {
                var propertyAccess = row.Property(column);
                if (TypeSemantics.IsEqual(functionImportReturnType.TypeUsage, column.TypeUsage))
                {
                    return(propertyAccess);
                }
                else
                {
                    return(propertyAccess.CastTo(functionImportReturnType.TypeUsage));
                }
            };

            queryExpression = queryExpression.Select(row => scalarView(row));
            return(queryExpression);
        }
Example #2
0
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            // The FROM part:
            //  - build a tree of binary joins out of the inputs (this.Children).
            //  - update each child block with its relative position in the join tree,
            //    so that QualifiedSlot and QualifiedCellIdBoolean objects could find their
            //    designated block areas inside the cumulative join row passed into their AsCqt(row) method.
            CqlBlock      leftmostBlock = this.Children[0];
            DbExpression  left          = leftmostBlock.AsCqt(false);
            List <string> joinTreeCtxParentQualifiers = new List <string>();

            for (int i = 1; i < this.Children.Count; ++i)
            {
                // Join the current left expression (a tree) to the current right block.
                CqlBlock     rightBlock = this.Children[i];
                DbExpression right      = rightBlock.AsCqt(false);
                Func <DbExpression, DbExpression, DbExpression> joinConditionFunc = m_onClauses[i - 1].AsCqt;
                DbJoinExpression join;
                switch (m_opType)
                {
                case CellTreeOpType.FOJ:
                    join = left.FullOuterJoin(right, joinConditionFunc);
                    break;

                case CellTreeOpType.IJ:
                    join = left.InnerJoin(right, joinConditionFunc);
                    break;

                case CellTreeOpType.LOJ:
                    join = left.LeftOuterJoin(right, joinConditionFunc);
                    break;

                default:
                    Debug.Fail("Unknown operator");
                    return(null);
                }

                if (i == 1)
                {
                    // Assign the joinTreeContext to the leftmost block.
                    leftmostBlock.SetJoinTreeContext(joinTreeCtxParentQualifiers, join.Left.VariableName);
                }
                else
                {
                    // Update the joinTreeCtxParentQualifiers.
                    // Note that all blocks that already participate in the left expression tree share the same copy of the joinTreeContext.
                    joinTreeCtxParentQualifiers.Add(join.Left.VariableName);
                }

                // Assign the joinTreeContext to the right block.
                rightBlock.SetJoinTreeContext(joinTreeCtxParentQualifiers, join.Right.VariableName);

                left = join;
            }

            // The SELECT part.
            return(left.Select(row => GenerateProjectionCqt(row, false)));
        }
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            DbExpression source = this.Children[0].AsCqt(false);

            if (!BoolExpression.EqualityComparer.Equals(this.WhereClause, BoolExpression.True))
            {
                source = (DbExpression)source.Where((Func <DbExpression, DbExpression>)(row => this.WhereClause.AsCqt(row)));
            }
            return((DbExpression)source.Select <DbExpression>((Func <DbExpression, DbExpression>)(row => this.GenerateProjectionCqt(row, isTopLevel))));
        }
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            DbExpression source = (DbExpression)this.m_extent.Scan();

            if (!BoolExpression.EqualityComparer.Equals(this.WhereClause, BoolExpression.True))
            {
                source = (DbExpression)source.Where((Func <DbExpression, DbExpression>)(row => this.WhereClause.AsCqt(row)));
            }
            DbExpression dbExpression = (DbExpression)source.Select <DbExpression>((Func <DbExpression, DbExpression>)(row => this.GenerateProjectionCqt(row, isTopLevel)));

            if (this.m_selectDistinct == CellQuery.SelectDistinct.Yes)
            {
                dbExpression = (DbExpression)dbExpression.Distinct();
            }
            return(dbExpression);
        }
Example #5
0
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            Debug.Assert(m_caseSlotInfo.OutputMember != null, "We only construct real slots not boolean slots");

            // The FROM part: FROM (childBlock)
            Debug.Assert(Children.Count == 1, "CaseCqlBlock can have exactly one child.");
            CqlBlock     childBlock = this.Children[0];
            DbExpression cqt        = childBlock.AsCqt(false);

            // Get the WHERE part only when the expression is not simply TRUE.
            if (!BoolExpression.EqualityComparer.Equals(this.WhereClause, BoolExpression.True))
            {
                cqt = cqt.Where(row => this.WhereClause.AsCqt(row));
            }

            // The SELECT part.
            return(cqt.Select(row => GenerateProjectionCqt(row, isTopLevel)));
        }
Example #6
0
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            CqlBlock      child1       = this.Children[0];
            DbExpression  dbExpression = child1.AsCqt(false);
            List <string> stringList   = new List <string>();

            for (int index = 1; index < this.Children.Count; ++index)
            {
                CqlBlock     child2 = this.Children[index];
                DbExpression right  = child2.AsCqt(false);
                Func <DbExpression, DbExpression, DbExpression> joinCondition = new Func <DbExpression, DbExpression, DbExpression>(this.m_onClauses[index - 1].AsCqt);
                DbJoinExpression dbJoinExpression;
                switch (this.m_opType)
                {
                case CellTreeOpType.FOJ:
                    dbJoinExpression = dbExpression.FullOuterJoin(right, joinCondition);
                    break;

                case CellTreeOpType.LOJ:
                    dbJoinExpression = dbExpression.LeftOuterJoin(right, joinCondition);
                    break;

                case CellTreeOpType.IJ:
                    dbJoinExpression = dbExpression.InnerJoin(right, joinCondition);
                    break;

                default:
                    return((DbExpression)null);
                }
                if (index == 1)
                {
                    child1.SetJoinTreeContext((IList <string>)stringList, dbJoinExpression.Left.VariableName);
                }
                else
                {
                    stringList.Add(dbJoinExpression.Left.VariableName);
                }
                child2.SetJoinTreeContext((IList <string>)stringList, dbJoinExpression.Right.VariableName);
                dbExpression = (DbExpression)dbJoinExpression;
            }
            return((DbExpression)dbExpression.Select <DbExpression>((Func <DbExpression, DbExpression>)(row => this.GenerateProjectionCqt(row, false))));
        }
Example #7
0
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            // Get the FROM part.
            DbExpression cqt = m_extent.Scan();

            // Get the WHERE part only when the expression is not simply TRUE.
            if (!BoolExpression.EqualityComparer.Equals(WhereClause, BoolExpression.True))
            {
                cqt = cqt.Where(row => WhereClause.AsCqt(row));
            }

            // The SELECT/DISTINCT part.
            cqt = cqt.Select(row => GenerateProjectionCqt(row, isTopLevel));
            if (m_selectDistinct == CellQuery.SelectDistinct.Yes)
            {
                cqt = cqt.Distinct();
            }

            return(cqt);
        }
Example #8
0
        private DbExpression GenerateScalarResultMappingView(
            DbExpression storeFunctionInvoke)
        {
            DbExpression   source = storeFunctionInvoke;
            CollectionType functionImportReturnType;

            MetadataHelper.TryGetFunctionImportReturnCollectionType(this.FunctionImport, 0, out functionImportReturnType);
            EdmProperty column = ((RowType)((CollectionType)source.ResultType.EdmType).TypeUsage.EdmType).Properties[0];
            Func <DbExpression, DbExpression> scalarView = (Func <DbExpression, DbExpression>)(row =>
            {
                DbPropertyExpression propertyExpression = row.Property(column);
                if (TypeSemantics.IsEqual(functionImportReturnType.TypeUsage, column.TypeUsage))
                {
                    return((DbExpression)propertyExpression);
                }
                return((DbExpression)propertyExpression.CastTo(functionImportReturnType.TypeUsage));
            });

            return((DbExpression)source.Select <DbExpression>((Func <DbExpression, DbExpression>)(row => scalarView(row))));
        }
            /// <summary>
            /// Returns the update or query view for an Extent as a
            /// string.
            /// There are a series of steps that we go through for discovering a view for an extent.
            /// To start with we assume that we are working with Generated Views. To find out the
            /// generated view we go to the ObjectItemCollection and see if it is not-null. If the ObjectItemCollection
            /// is non-null, we get the view generation assemblies that it might have cached during the
            /// Object metadata discovery.If there are no view generation assemblies we switch to the
            /// runtime view generation strategy. If there are view generation assemblies, we get the list and
            /// go through them and see if there are any assemblies that are there from which we have not already loaded
            /// the views. We collect the views from assemblies that we have not already collected from earlier.
            /// If the ObjectItemCollection is null and we are in the view generation mode, that means that
            /// the query or update is issued from the Value layer and this is the first time view has been asked for.
            /// The compile time view gen for value layer queries will work for very simple scenarios.
            /// If the users wants to get the performance benefit, they should call MetadataWorkspace.LoadFromAssembly.
            /// At this point we go through the referenced assemblies of the entry assembly( this wont work for Asp.net
            /// or if the viewgen assembly was not referenced by the executing application).
            /// and try to see if there were any view gen assemblies. If there are, we collect the views for all extents.
            /// Once we have all the generated views gathered, we try to get the view for the extent passed in.
            /// If we find one we will return it. If we can't find one an exception will be thrown.
            /// If there were no view gen assemblies either in the ObjectItemCollection or in the list of referenced
            /// assemblies of calling assembly, we change the mode to runtime view generation and will continue to
            /// be in that mode for the rest of the lifetime of the mapping item collection.
            /// </summary>
            internal GeneratedView GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection)
            {
                //First check if we have collected a view from user-defined query views
                //Dont need to worry whether to generate Query view or update viw, because that is relative to the extent.
                GeneratedView view;

                if (TryGetUserDefinedQueryView(extent, out view))
                {
                    return(view);
                }

                //If this is a foreign key association, manufacture a view on the fly.
                if (extent.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
                {
                    AssociationSet aSet = (AssociationSet)extent;
                    if (aSet.ElementType.IsForeignKey)
                    {
                        if (m_config.IsViewTracing)
                        {
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.FormatTraceLine("================= Generating FK Query View for: {0} =================", aSet.Name);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty);
                        }

                        // Although we expose a collection of constraints in the API, there is only ever one constraint.
                        Debug.Assert(aSet.ElementType.ReferentialConstraints.Count == 1, "aSet.ElementType.ReferentialConstraints.Count == 1");
                        ReferentialConstraint rc = aSet.ElementType.ReferentialConstraints.Single();

                        EntitySet dependentSet = aSet.AssociationSetEnds[rc.ToRole.Name].EntitySet;
                        EntitySet principalSet = aSet.AssociationSetEnds[rc.FromRole.Name].EntitySet;

                        DbExpression qView = dependentSet.Scan();

                        // Introduce an OfType view if the dependent end is a subtype of the entity set
                        EntityType dependentType = MetadataHelper.GetEntityTypeForEnd((AssociationEndMember)rc.ToRole);
                        EntityType principalType = MetadataHelper.GetEntityTypeForEnd((AssociationEndMember)rc.FromRole);
                        if (dependentSet.ElementType.IsBaseTypeOf(dependentType))
                        {
                            qView = qView.OfType(TypeUsage.Create(dependentType));
                        }

                        if (rc.FromRole.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)
                        {
                            // Filter out instances with existing relationships.
                            qView = qView.Where(e =>
                            {
                                DbExpression filter = null;
                                foreach (EdmProperty fkProp in rc.ToProperties)
                                {
                                    DbExpression notIsNull = e.Property(fkProp).IsNull().Not();
                                    filter = null == filter ? notIsNull : filter.And(notIsNull);
                                }
                                return(filter);
                            });
                        }
                        qView = qView.Select(e =>
                        {
                            List <DbExpression> ends = new List <DbExpression>();
                            foreach (AssociationEndMember end in aSet.ElementType.AssociationEndMembers)
                            {
                                if (end.Name == rc.ToRole.Name)
                                {
                                    var keyValues = new List <KeyValuePair <string, DbExpression> >();
                                    foreach (EdmMember keyMember in dependentSet.ElementType.KeyMembers)
                                    {
                                        keyValues.Add(e.Property((EdmProperty)keyMember));
                                    }
                                    ends.Add(dependentSet.RefFromKey(DbExpressionBuilder.NewRow(keyValues), dependentType));
                                }
                                else
                                {
                                    // Manufacture a key using key values.
                                    var keyValues = new List <KeyValuePair <string, DbExpression> >();
                                    foreach (EdmMember keyMember in principalSet.ElementType.KeyMembers)
                                    {
                                        int offset = rc.FromProperties.IndexOf((EdmProperty)keyMember);
                                        keyValues.Add(e.Property(rc.ToProperties[offset]));
                                    }
                                    ends.Add(principalSet.RefFromKey(DbExpressionBuilder.NewRow(keyValues), principalType));
                                }
                            }
                            return(TypeUsage.Create(aSet.ElementType).New(ends));
                        });
                        return(GeneratedView.CreateGeneratedViewForFKAssociationSet(aSet, aSet.ElementType, new DbQueryCommandTree(workspace, DataSpace.SSpace, qView), storageMappingItemCollection, m_config));
                    }
                }

                // If no User-defined QV is found, call memoized View Generation procedure.
                Dictionary <EntitySetBase, GeneratedView> generatedViews = m_generatedViewsMemoizer.Evaluate(extent.EntityContainer);

                if (!generatedViews.TryGetValue(extent, out view))
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Views_For_Extent_Not_Generated(
                                                          (extent.EntityContainer.DataSpace == DataSpace.SSpace)?"Table":"EntitySet", extent.Name));
                }

                return(view);
            }