Esempio n. 1
0
        /// <summary>
        /// Perform the query
        /// </summary>
        protected virtual IEnumerable <Object> DoQueryInternal(DataContext context, Expression <Func <TModel, bool> > primaryQuery, Guid queryId, int offset, int?count, out int totalResults, ModelSort <TModel>[] orderBy, bool includeCount = true, bool overrideFuzzyTotalSetting = false)
        {
#if DEBUG
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif

            OrmResultSet <TQueryReturn>         retVal  = null;
            Expression <Func <TModel, bool> >[] queries = new Expression <Func <TModel, bool> >[] { primaryQuery };
            // Are we intersecting?
            if (context.Data.TryGetValue("UNION", out object others) &&
                others is Expression <Func <TModel, bool> >[])
            {
                context.Data.Remove("UNION");
                queries = queries.Concat((Expression <Func <TModel, bool> >[])others).ToArray();
            }

            try
            {
                // Fetch queries
                foreach (var q in queries)
                {
                    var          query       = q;
                    SqlStatement domainQuery = null;
                    // Query has been registered?
                    if (queryId != Guid.Empty && this.m_queryPersistence?.IsRegistered(queryId) == true)
                    {
                        return(this.GetStoredQueryResults(queryId, offset, count, out totalResults));
                    }

                    // Is obsoletion time already specified? If so and the entity is an iversioned entity we don't want obsolete data coming back
                    var queryString = query.ToString();
                    if (!queryString.Contains("ObsoletionTime") && typeof(IVersionedEntity).IsAssignableFrom(typeof(TModel)) && !queryString.Contains("VersionKey"))
                    {
                        var obsoletionReference = Expression.MakeBinary(ExpressionType.Equal, Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(BaseEntityData.ObsoletionTime))), Expression.Constant(null));
                        //var obsoletionReference = Expression.MakeUnary(ExpressionType.Not, Expression.MakeMemberAccess(Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(BaseEntityData.ObsoletionTime))), typeof(Nullable<DateTimeOffset>).GetProperty("HasValue")), typeof(bool));
                        query = Expression.Lambda <Func <TModel, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, obsoletionReference, query.Body), query.Parameters);
                    }
                    else if (!queryString.Contains("ObsoleteVersionSequenceId") && typeof(IVersionedAssociation).IsAssignableFrom(typeof(TModel)))
                    {
                        var obsoletionReference = Expression.MakeBinary(ExpressionType.Equal, Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(IVersionedAssociation.ObsoleteVersionSequenceId))), Expression.Constant(null));
                        //var obsoletionReference = Expression.MakeUnary(ExpressionType.Not, Expression.MakeMemberAccess(Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(IVersionedAssociation.ObsoleteVersionSequenceId))), typeof(Nullable<decimal>).GetProperty("HasValue")), typeof(bool));
                        query = Expression.Lambda <Func <TModel, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, obsoletionReference, query.Body), query.Parameters);
                    }

                    // Domain query
                    Type[] selectTypes = { typeof(TQueryReturn) };
                    if (selectTypes[0].IsConstructedGenericType)
                    {
                        selectTypes = selectTypes[0].GenericTypeArguments;
                    }

                    domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom(selectTypes);
                    var expression = m_mapper.MapModelExpression <TModel, TDomain, bool>(query, false);
                    if (expression != null)
                    {
                        Type lastJoined = typeof(TDomain);
                        if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn)))
                        {
                            foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => this.m_persistenceService.GetMapper().MapModelType(o)))
                            {
                                if (p != typeof(TDomain))
                                {
                                    // Find the FK to join
                                    domainQuery.InnerJoin(lastJoined, p);
                                    lastJoined = p;
                                }
                            }
                        }

                        domainQuery.Where <TDomain>(expression);
                    }
                    else
                    {
                        m_tracer.TraceEvent(EventLevel.Verbose, "Will use slow query construction due to complex mapped fields");
                        domainQuery = this.m_persistenceService.GetQueryBuilder().CreateQuery(query, orderBy);
                    }



                    if (retVal == null)
                    {
                        retVal = this.DomainQueryInternal <TQueryReturn>(context, domainQuery);
                    }
                    else
                    {
                        retVal = retVal.Union(this.DomainQueryInternal <TQueryReturn>(context, domainQuery));
                    }
                }

                this.AppendOrderBy(retVal.Statement, orderBy);

                // Count = 0 means we're not actually fetching anything so just hit the db
                if (count != 0)
                {
                    // Stateful query identifier = We need to add query results
                    if (queryId != Guid.Empty && ApplicationContext.Current.GetService <IQueryPersistenceService>() != null)
                    {
                        // Create on a separate thread the query results
                        var keys = retVal.Keys <Guid>().ToArray();
                        totalResults = keys.Length;
                        this.m_queryPersistence?.RegisterQuerySet(queryId, keys, queries, totalResults);
                    }
                    else if (count.HasValue && includeCount && !m_configuration.UseFuzzyTotals) // Get an exact total
                    {
                        totalResults = retVal.Count();
                    }
                    else
                    {
                        totalResults = 0;
                    }

                    // Fuzzy totals - This will only fetch COUNT + 1 as the total results
                    if (count.HasValue)
                    {
                        if ((overrideFuzzyTotalSetting || m_configuration.UseFuzzyTotals) && totalResults == 0)
                        {
                            var fuzzResults = retVal.Skip(offset).Take(count.Value + 1).OfType <Object>().ToList();
                            totalResults = fuzzResults.Count();
                            return(fuzzResults.Take(count.Value));
                        }
                        else
                        {
                            return(retVal.Skip(offset).Take(count.Value).OfType <Object>());
                        }
                    }
                    else
                    {
                        return(retVal.Skip(offset).OfType <Object>());
                    }
                }
                else
                {
                    totalResults = retVal.Count();
                    return(new List <Object>());
                }
            }
            catch (Exception ex)
            {
                this.m_tracer.TraceError("Error performing underlying query: {0}", ex);
                if (retVal != null)
                {
                    this.m_tracer.TraceEvent(EventLevel.Error, context.GetQueryLiteral(retVal.ToSqlStatement()));
                }
                context.Dispose(); // No longer important

                throw;
            }
#if DEBUG
            finally
            {
                sw.Stop();
            }
#endif
        }
Esempio n. 2
0
        /// <summary>
        /// Perform the query
        /// </summary>
        protected virtual IEnumerable <Object> QueryInternal(DataContext context, Expression <Func <TModel, bool> > query, Guid queryId, int offset, int?count, out int totalResults, bool incudeCount = true)
        {
#if DEBUG
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif

            SqlStatement domainQuery = null;
            try
            {
                // Query has been registered?
                if (queryId != Guid.Empty && this.m_queryPersistence?.IsRegistered(queryId.ToString()) == true)
                {
                    totalResults = (int)this.m_queryPersistence.QueryResultTotalQuantity(queryId.ToString());
                    var resultKeys = this.m_queryPersistence.GetQueryResults <Guid>(queryId.ToString(), offset, count.Value);
                    return(resultKeys.Select(p => p.Id).OfType <Object>());
                }

                // Is obsoletion time already specified?
                if (!query.ToString().Contains("ObsoletionTime") && typeof(BaseEntityData).IsAssignableFrom(typeof(TModel)))
                {
                    var obsoletionReference = Expression.MakeBinary(ExpressionType.Equal, Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(BaseEntityData.ObsoletionTime))), Expression.Constant(null));
                    query = Expression.Lambda <Func <TModel, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, obsoletionReference, query.Body), query.Parameters);
                }

                // Domain query
                domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom();
                var expression = m_mapper.MapModelExpression <TModel, TDomain>(query, false);
                if (expression != null)
                {
                    Type lastJoined = typeof(TDomain);
                    if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn)))
                    {
                        foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => AdoPersistenceService.GetMapper().MapModelType(o)))
                        {
                            if (p != typeof(TDomain))
                            {
                                // Find the FK to join
                                domainQuery.InnerJoin(lastJoined, p);
                                lastJoined = p;
                            }
                        }
                    }

                    domainQuery.Where <TDomain>(expression);
                }
                else
                {
                    m_tracer.TraceEvent(System.Diagnostics.TraceEventType.Verbose, 0, "Will use slow query construction due to complex mapped fields");
                    domainQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery(query);
                }

                // Count = 0 means we're not actually fetching anything so just hit the db
                if (count != 0)
                {
                    domainQuery = this.AppendOrderBy(domainQuery);

                    // Query id just get the UUIDs in the db
                    if (queryId != Guid.Empty && count != 0)
                    {
                        ColumnMapping pkColumn = null;
                        if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn)))
                        {
                            foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => AdoPersistenceService.GetMapper().MapModelType(o)))
                            {
                                if (!typeof(DbSubTable).IsAssignableFrom(p) && !typeof(IDbVersionedData).IsAssignableFrom(p))
                                {
                                    pkColumn = TableMapping.Get(p).Columns.SingleOrDefault(o => o.IsPrimaryKey);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            pkColumn = TableMapping.Get(typeof(TQueryReturn)).Columns.SingleOrDefault(o => o.IsPrimaryKey);
                        }

                        var keyQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery(query, pkColumn).Build();

                        var resultKeys = context.Query <Guid>(keyQuery.Build());

                        //ApplicationContext.Current.GetService<IThreadPoolService>().QueueNonPooledWorkItem(a => this.m_queryPersistence?.RegisterQuerySet(queryId.ToString(), resultKeys.Select(o => new Identifier<Guid>(o)).ToArray(), query), null);
                        // Another check
                        this.m_queryPersistence?.RegisterQuerySet(queryId.ToString(), resultKeys.Count(), resultKeys.Select(o => new Identifier <Guid>(o)).Take(1000).ToArray(), query);

                        ApplicationContext.Current.GetService <IThreadPoolService>().QueueNonPooledWorkItem(o =>
                        {
                            int ofs   = 1000;
                            var rkeys = o as Guid[];
                            while (ofs < rkeys.Length)
                            {
                                this.m_queryPersistence?.AddResults(queryId.ToString(), rkeys.Skip(ofs).Take(1000).Select(k => new Identifier <Guid>(k)).ToArray());
                                ofs += 1000;
                            }
                        }, resultKeys.ToArray());

                        if (incudeCount)
                        {
                            totalResults = (int)resultKeys.Count();
                        }
                        else
                        {
                            totalResults = 0;
                        }

                        var retVal = resultKeys.Skip(offset);
                        if (count.HasValue)
                        {
                            retVal = retVal.Take(count.Value);
                        }
                        return(retVal.OfType <Object>());
                    }
                    else if (incudeCount)
                    {
                        totalResults = context.Count(domainQuery);
                        if (totalResults == 0)
                        {
                            return(new List <Object>());
                        }
                    }
                    else
                    {
                        totalResults = 0;
                    }

                    if (offset > 0)
                    {
                        domainQuery.Offset(offset);
                    }
                    if (count.HasValue)
                    {
                        domainQuery.Limit(count.Value);
                    }

                    return(this.DomainQueryInternal <TQueryReturn>(context, domainQuery, ref totalResults).OfType <Object>());
                }
                else
                {
                    totalResults = context.Count(domainQuery);
                    return(new List <Object>());
                }
            }
            catch (Exception ex)
            {
                if (domainQuery != null)
                {
                    this.m_tracer.TraceEvent(TraceEventType.Error, ex.HResult, context.GetQueryLiteral(domainQuery.Build()));
                }
                context.Dispose(); // No longer important

                throw;
            }
#if DEBUG
            finally
            {
                sw.Stop();
            }
#endif
        }
        /// <summary>
        /// Queries for the specified model.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="query">The query.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="count">The count.</param>
        /// <param name="totalResults">The total results.</param>
        /// <param name="countResults">if set to <c>true</c> [count results].</param>
        /// <param name="overrideAuthContext">The principal to use instead of the default.</param>
        /// <returns>Returns a list of the specified model instance which match the given query expression.</returns>
        public override IEnumerable <TModel> QueryInternal(DataContext context, Expression <Func <TModel, bool> > query, int offset, int?count, out int totalResults, bool countResults)
        {
            try
            {
                // Domain query
                SqlStatement domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom();

                var expression = ModelMapper.MapModelExpression <TModel, TDomain, bool>(query, false);

                if (expression != null)
                {
                    Type lastJoined = typeof(TDomain);
                    if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn)))
                    {
                        foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => ReportingPersistenceService.ModelMapper.MapModelType(o)))
                        {
                            if (p != typeof(TDomain))
                            {
                                // Find the FK to join
                                domainQuery.InnerJoin(lastJoined, p);
                                lastJoined = p;
                            }
                        }
                    }

                    domainQuery.Where(expression);
                }
                else
                {
                    this.traceSource.TraceEvent(EventLevel.Verbose, "Will use slow query construction due to complex mapped fields");
                    domainQuery = ReportingPersistenceService.QueryBuilder.CreateQuery(query);
                }

                // Build and see if the query already exists on the stack???
                domainQuery = domainQuery.Build();

                if (Configuration.TraceSql)
                {
                    traceSource.TraceEvent(EventLevel.Verbose, "Trace SQL flag is set to true, printing SQL statement");
                    traceSource.TraceEvent(EventLevel.Verbose, $"GENERATED SQL STATEMENT: {domainQuery.SQL}");
                }

                if (offset > 0)
                {
                    domainQuery.Offset(offset);
                }
                if (count.HasValue)
                {
                    domainQuery.Limit(count.Value);
                }

                var results = context.Query <TQueryReturn>(domainQuery).OfType <object>();
                totalResults = results.Count();

                return(results.Select(r => ToModelInstance(r, context)));
            }
            catch (Exception e)
            {
                traceSource.TraceEvent(EventLevel.Error, $"Unable to query: {e}");
                throw;
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Perform the query
        /// </summary>
        protected virtual IEnumerable <Object> QueryInternalEx(DataContext context, Expression <Func <TModel, bool> > query, Guid queryId, int offset, int?count, out int totalResults, bool incudeCount, ModelSort <TModel>[] orderBy)
        {
#if DEBUG
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif

            SqlStatement domainQuery = null;
            try
            {
                // Query has been registered?
                if (queryId != Guid.Empty && this.m_queryPersistence?.IsRegistered(queryId) == true)
                {
                    totalResults = (int)this.m_queryPersistence.QueryResultTotalQuantity(queryId);
                    var resultKeys = this.m_queryPersistence.GetQueryResults(queryId, offset, count.Value);
                    return(resultKeys.OfType <Object>());
                }

                // Is obsoletion time already specified?
                if (!query.ToString().Contains("ObsoletionTime") && typeof(BaseEntityData).IsAssignableFrom(typeof(TModel)))
                {
                    var obsoletionReference = Expression.MakeBinary(ExpressionType.Equal, Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(BaseEntityData.ObsoletionTime))), Expression.Constant(null));
                    query = Expression.Lambda <Func <TModel, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, obsoletionReference, query.Body), query.Parameters);
                }

                // Domain query
                domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom();
                var expression = m_mapper.MapModelExpression <TModel, TDomain, bool>(query, false);
                if (expression != null)
                {
                    Type lastJoined = typeof(TDomain);
                    if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn)))
                    {
                        foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => AdoAuditPersistenceService.GetMapper().MapModelType(o)))
                        {
                            if (p != typeof(TDomain))
                            {
                                // Find the FK to join
                                domainQuery.InnerJoin(lastJoined, p);
                                lastJoined = p;
                            }
                        }
                    }

                    domainQuery.Where <TDomain>(expression);
                }
                else
                {
                    m_tracer.TraceVerbose("Will use slow query construction due to complex mapped fields");
                    domainQuery = AdoAuditPersistenceService.GetQueryBuilder().CreateQuery(query, orderBy);
                }


                var retVal = this.DomainQueryInternal <TQueryReturn>(context, domainQuery);
                this.AppendOrderBy(retVal.Statement, orderBy);

                // Count = 0 means we're not actually fetching anything so just hit the db
                if (count != 0)
                {
                    // Stateful query identifier = We need to add query results
                    if (queryId != Guid.Empty && ApplicationServiceContext.Current.GetService <IQueryPersistenceService>() != null)
                    {
                        // Create on a separate thread the query results
                        var keys = retVal.Keys <Guid>().ToArray();
                        totalResults = keys.Length;
                        this.m_queryPersistence?.RegisterQuerySet(queryId, keys, query, totalResults);
                    }
                    else if (count.HasValue && !AdoAuditPersistenceService.GetConfiguration().UseFuzzyTotals) // Get an exact total
                    {
                        totalResults = retVal.Count();
                    }
                    else
                    {
                        totalResults = 0;
                    }

                    // Fuzzy totals - This will only fetch COUNT + 1 as the total results
                    if (count.HasValue)
                    {
                        if ((AdoAuditPersistenceService.GetConfiguration().UseFuzzyTotals) && totalResults == 0)
                        {
                            var fuzzResults = retVal.Skip(offset).Take(count.Value + 1).OfType <Object>().ToList();
                            totalResults = offset + fuzzResults.Count();
                            return(fuzzResults.Take(count.Value));
                        }
                        else
                        {
                            return(retVal.Skip(offset).Take(count.Value).OfType <Object>());
                        }
                    }
                    else
                    {
                        return(retVal.Skip(offset).OfType <Object>());
                    }
                }
                else
                {
                    totalResults = retVal.Count();
                    return(new List <Object>());
                }
            }
            catch (Exception ex)
            {
                if (domainQuery != null)
                {
                    this.m_tracer.TraceError(context.GetQueryLiteral(domainQuery.Build()));
                }
                context.Dispose(); // No longer important

                throw;
            }
#if DEBUG
            finally
            {
                sw.Stop();
            }
#endif
        }