예제 #1
0
        public void Check_StructuredQuery_Invalidation_On_ReportInterface( )
        {
            using (CacheManager.EnforceCacheHitRules(false))
            {
                Report             report;
                ResourceReportNode rootNode;
                ResourceArgument   exprType;

                // Create report
                using (var ctx = DatabaseContext.GetContext(true, preventPostSaveActionsPropagating: true))
                {
                    report   = new EntityModel.Report();
                    rootNode = new ResourceReportNode();
                    var reportType = EntityModel.Entity.Get <EntityType>("test:person");;
                    rootNode.ResourceReportNodeType = reportType;
                    report.RootNode = rootNode.As <ReportNode>();
                    var column = new EntityModel.ReportColumn( );
                    exprType = new ResourceArgument();
                    exprType.ConformsToType = reportType;
                    var expr = new EntityModel.ResourceExpression();
                    expr.ReportExpressionResultType = exprType.As <ActivityArgument>();
                    expr.SourceNode         = rootNode.As <ReportNode>();
                    column.ColumnExpression = expr.As <ReportExpression>();
                    report.ReportColumns.Add(column);
                    report.Save();
                    ctx.CommitTransaction();
                }

                ReportingInterface ri = new ReportingInterface( );
                var settings          = new ReportSettings
                {
                    InitialRow           = 0,
                    PageSize             = 1,
                    RequireFullMetadata  = true,
                    RequireBasicMetadata = true
                };

                // Run and expect 1 column
                var result = ri.RunReport(report.Id, settings);
                Assert.AreEqual(1, result.ReportQueryColumns.Count);

                // Add column
                using (var ctx = DatabaseContext.GetContext(true, preventPostSaveActionsPropagating: true))
                {
                    var column2 = new EntityModel.ReportColumn();
                    var expr2   = new EntityModel.ResourceExpression();
                    expr2.SourceNode = rootNode.As <ReportNode>();
                    expr2.ReportExpressionResultType = exprType.As <ActivityArgument>();
                    column2.ColumnExpression         = expr2.As <ReportExpression>();
                    report.ReportColumns.Add(column2);
                    report.Save();
                    ctx.CommitTransaction();
                }

                // Run and expect 2 columns
                result = ri.RunReport(report.Id, settings);
                Assert.AreEqual(2, result.ReportQueryColumns.Count);
            }
        }
예제 #2
0
        /// <summary>
        /// Get the structured query, possibly from cache.
        /// </summary>
        /// <param name="report">The report to convert.</param>
        /// <param name="settings">The report run settings.</param>
        /// <param name="suppressPreload">True if we should suppress preloading.</param>
        /// <returns>The structured query.</returns>
        private StructuredQuery GetStructuredQuery(Model.Report report, ReportSettings settings, bool suppressPreload)
        {
            using (MessageContext msg = new MessageContext("Reports"))
            {
                StructuredQuery immutableStructuredQuery;
                StructuredQuery structuredQuery;

                bool useStructuredQueryCache = settings.UseStructuredQueryCache;

                ReportToQueryConverterSettings converterSettings = new ReportToQueryConverterSettings
                {
                    SuppressPreload = suppressPreload,
                    RefreshCachedStructuredQuery = settings.RefreshCachedStructuredQuery,
                    SchemaOnly = settings.RequireSchemaMetadata
                };

                if (settings != null && settings.UseStructuredQueryCache)
                {
                    // don't allow mutations of cached copy
                    immutableStructuredQuery = CachedReportToQueryConverter.Convert(report, converterSettings);
                }
                else
                {
                    // don't allow mutations, just so we can log it correctly
                    immutableStructuredQuery = NonCachedReportToQueryConverter.Convert(report, converterSettings);
                }

                structuredQuery = immutableStructuredQuery.DeepCopy( ); // so we can mutate it (in case we need to)

                // Logging
                msg.Append(() => new String('-', 50));
                msg.Append(() => "GetStructuredQuery");
                msg.Append(() => "suppressPreload = " + suppressPreload);
                msg.Append(() => "useStructuredQueryCache = " + useStructuredQueryCache);
                msg.Append(() => "Structured Query:\n" + StructuredQueryHelper.ToXml(immutableStructuredQuery));
                msg.Append(() => new String('-', 50));

                return(structuredQuery);
            }
        }
예제 #3
0
        private PreparedQuery PrepareReportRollupRun(Model.Report report, StructuredQuery structuredQuery, ReportSettings reportSettings, QuerySettings nonRollupQuerySettings)
        {
            StructuredQuery rollupQuery     = null;
            ClientAggregate clientAggregate = null;
            StructuredQuery optimisedQuery;
            QuerySettings   rollupSettings;
            bool            adhocRollup;
            bool            reportRollup;

            adhocRollup  = reportSettings.ReportParameters != null && reportSettings.ReportParameters.GroupAggregateRules != null;
            reportRollup = !adhocRollup && report.ReportColumns.Any(rc => rc.ColumnRollup.Count > 0 || rc.ColumnGrouping.Count > 0);

            if (adhocRollup)
            {
                clientAggregate = ApplyAdhocAggregates(reportSettings.ReportParameters.GroupAggregateRules, structuredQuery);
            }
            else if (reportRollup)
            {
                clientAggregate = new ClientAggregate(report, structuredQuery);
                clientAggregate.IncludeRollup = true;
            }
            else if (report.RollupGrandTotals != null || report.RollupSubTotals != null || report.RollupOptionLabels != null)
            {
                return(new PreparedQuery
                {
                    ClientAggregate = new ClientAggregate( )
                });
            }
            else
            {
                return(new PreparedQuery( ));
            }

            // Clone the query, so that runs and rollups won't intefere with each others caches if they mutate the structure
            // In particular, calculated columns get evaluated during execution and mutate the query .. but only if the result doesn't come from cache, but this interferes with the rollup cache key.
            // Ideally, both calculations and optimisations would be provided in layers, and both applied, and cached, before either normal or rollup executions are run.
            rollupQuery = structuredQuery.DeepCopy( );

            // A poor proxy for determining that this is not a pivot chart.
            bool isGroupedReport = !(reportSettings.ReportParameters != null &&
                                     reportSettings.ReportParameters.GroupAggregateRules != null &&
                                     reportSettings.ReportParameters.GroupAggregateRules.IgnoreRows);

            if (isGroupedReport)
            {
                ReportRollupHelper.EnsureShowTotalsHasCount(rollupQuery, clientAggregate);
            }

            // Remove unused columns
            bool supportQuickSearch = !string.IsNullOrWhiteSpace(reportSettings.QuickSearch);

            optimisedQuery = ReportRollupHelper.RemoveUnusedColumns(rollupQuery, clientAggregate, supportQuickSearch);

            rollupSettings = new QuerySettings
            {
                SecureQuery             = nonRollupQuerySettings.SecureQuery,
                SupportClientAggregate  = true,
                SupportPaging           = false,
                QuickSearchTerm         = reportSettings.QuickSearch,
                SupportQuickSearch      = supportQuickSearch, // rollups query support quick search.
                ClientAggregate         = clientAggregate,
                AdditionalOrderColumns  = BuildAdditionOrderColumnDictionary(optimisedQuery, clientAggregate),
                FullAggregateClustering = true,
                Hint             = "RptRollup-" + report.Id,
                TargetResource   = nonRollupQuerySettings.TargetResource,
                IncludeResources = nonRollupQuerySettings.IncludeResources,
                ExcludeResources = nonRollupQuerySettings.ExcludeResources
            };
            // Note : do not apply quick search filter to rollups (for scalability reasons)


            PreparedQuery preparedQuery = new PreparedQuery
            {
                ClientAggregate = clientAggregate,
                StructuredQuery = optimisedQuery,
                QuerySettings   = rollupSettings
            };

            return(preparedQuery);
        }
예제 #4
0
        /// <summary>
        /// Runs the report.
        /// </summary>
        /// <param name="report">The report.</param>
        /// <param name="reportSettings">The settings.</param>
        /// <param name="suppressPreload">Pass true if the report has already been preloaded.</param>
        /// <returns>ReportResult.</returns>
        /// <exception cref="System.ArgumentException">@The report identifier resource is not a report.;reportId</exception>
        public ReportCompletionData PrepareReport(Model.Report report, ReportSettings reportSettings, bool suppressPreload = false)
        {
            if (report == null)
            {
                throw new ArgumentNullException("report");
            }
            if (reportSettings == null)
            {
                reportSettings = new ReportSettings( );
            }

            StructuredQuery structuredQuery;
            PreparedQuery   preparedReport;
            PreparedQuery   preparedRollup;

            using (EDC.ReadiNow.Diagnostics.Profiler.Measure("Prepare report run"))
                using (MessageContext messageContext = new MessageContext("Reports"))
                    using (new SecurityBypassContext( ))
                    {
                        // Get the structured query
                        structuredQuery = GetStructuredQuery(report, reportSettings, suppressPreload);

                        // Handle metadata-only request
                        if (reportSettings.RequireSchemaMetadata)
                        {
                            ReportResult reportResult = new ReportResult(report, structuredQuery, null, null, null, reportSettings);
                            return(new ReportCompletionData(reportResult));
                        }

                        // Prepare query settings
                        preparedReport = PrepareReportRun(structuredQuery, reportSettings);
                        preparedReport.QuerySettings.Hint = "Rpt-" + report.Id.ToString( );

                        // Handle rollups
                        preparedRollup = PrepareReportRollupRun(report, preparedReport.StructuredQuery, reportSettings, preparedReport.QuerySettings);
                    }

            Func <ReportResult> resultCallback = () =>
            {
                ReportResult reportResult = null;
                QueryResult  queryResult  = null;
                QueryResult  rollupResult = null;

                using (new SecurityBypassContext( ))
                {
                    // Execute the query
                    queryResult = QueryRunner.ExecuteQuery(preparedReport.StructuredQuery, preparedReport.QuerySettings);

                    // Execute the rollup query
                    if (preparedRollup.StructuredQuery != null)
                    {
                        rollupResult = QueryRunner.ExecuteQuery(preparedRollup.StructuredQuery, preparedRollup.QuerySettings);
                    }

                    // Package up the result.
                    reportResult = new ReportResult(report,
                                                    preparedReport.StructuredQuery, queryResult,
                                                    preparedRollup.ClientAggregate, rollupResult,
                                                    reportSettings);
                }

                return(reportResult);
            };

            // Create cache key (null indicates report is not cacheable)
            IQueryRunnerCacheKey reportCacheKey       = null;
            IQueryRunnerCacheKey rollupCacheKey       = null;
            ReportResultCacheKey reportResultCacheKey = null;

            reportCacheKey = QueryRunnerCacheKeyProvider.CreateCacheKey(preparedReport.StructuredQuery, preparedReport.QuerySettings);
            if (reportCacheKey != null)
            {
                if (preparedRollup.StructuredQuery != null)
                {
                    rollupCacheKey = QueryRunnerCacheKeyProvider.CreateCacheKey(preparedRollup.StructuredQuery, preparedRollup.QuerySettings);
                }
                reportResultCacheKey = new ReportResultCacheKey(reportSettings, reportCacheKey, rollupCacheKey);
            }

            // Create completion result
            ReportCompletionData completionData = new ReportCompletionData( );

            completionData.ResultCallback = resultCallback;
            completionData.ResultCacheKey = reportResultCacheKey;
            completionData.CacheContextDuringPreparation = CacheContext.GetContext( );

            return(completionData);
        }
예제 #5
0
        /// <summary>
        /// Runs the report.
        /// </summary>
        /// <param name="report">The report.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="suppressPreload">Pass true if the report has already been preloaded.</param>
        /// <returns>ReportResult.</returns>
        /// <exception cref="System.ArgumentException">@The report identifier resource is not a report.;reportId</exception>
        public ReportResult RunReport(Model.Report report, ReportSettings settings, bool suppressPreload = false)
        {
            ReportCompletionData completionData = PrepareReport(report, settings, suppressPreload);

            return(completionData.PerformRun( ));
        }