Esempio n. 1
0
        public override IEnumerable <T> PerformExecuteMany <T>(QueryDescription query, ObjectBinder objectBinder)
        {
            var direction = query.From.HierarchyScope;

            var disconnected = new NhQueryOverVisitor().Visit(query.Criteria);

            var revisionStatus = query.From.RevisionStatusType != FromClause.RevisionStatusNotSpecifiedType ? query.From.RevisionStatusType : null;

            var nodeIds = GetNodeIds(query);

            var buildVersionedQuery = Helper.GenerateVersionedQueryPlusAttributes(nodeIds, revisionStatus: revisionStatus, limitToLatestRevision: true, sortClauses: query.SortClauses);

            // If the criteria is null then the disconnected Id filter will be null too
            var queryOver = disconnected != null
                                ? buildVersionedQuery.WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(disconnected)
                                : buildVersionedQuery;

            IEnumerable <NodeVersion> resultBuilder = Enumerable.Empty <NodeVersion>();

            // Need to order in memory using the materialised results because the field name is the value of a column in the resultset, not a column itself
            // First materialise the results. Note that the Take / Skip is inefficient atm; NH bugs in Skip / Take in 3.0 causing same results irrespective of request, so enumerating whole list and skipping in memory (ouch)
            // https://nhibernate.jira.com/browse/NH-2917
            resultBuilder = queryOver.List().Distinct().ToArray();
            resultBuilder = OrderMaterialisedResults(query, resultBuilder);

            switch (query.ResultFilter.ResultFilterType)
            {
            case ResultFilterType.Take:
                resultBuilder = resultBuilder.Take(query.ResultFilter.SelectorArgument);
                break;

            case ResultFilterType.Skip:
                resultBuilder = resultBuilder.Skip(query.ResultFilter.SelectorArgument);
                break;

            default:
                //resultBuilder = queryOver.List();
                break;
            }

            //if (typeof(T).IsAssignableFrom(query.ResultFilter.ResultType))
            if (TypeFinder.IsTypeAssignableFrom(query.ResultFilter.ResultType, typeof(T)))
            {
                var nodeVersions = resultBuilder.Distinct();
                return(nodeVersions.Select(node => FrameworkContext.TypeMappers.Map <T>(node)));
                //return resultBuilder.Select(node => objectBinder.Execute(_fieldBinderFactory.Invoke(node))).Cast<T>();
            }

            return(Enumerable.Empty <T>());
        }
Esempio n. 2
0
        public override T PerformExecuteScalar <T>(QueryDescription query, ObjectBinder objectBinder)
        {
            var disconnected   = new NhQueryOverVisitor().Visit(query.Criteria);
            var revisionStatus = query.From.RevisionStatusType != FromClause.RevisionStatusNotSpecifiedType ? query.From.RevisionStatusType : null;

            NodeVersion outerVersionSelectorAlias = null;
            var         nodeIds             = GetNodeIds(query);
            var         buildVersionedQuery = Helper.GenerateVersionedQueryPlusAttributes(nodeIds, revisionStatus: revisionStatus, limitToLatestRevision: true);

            switch (query.ResultFilter.ResultFilterType)
            {
            case ResultFilterType.Any:
                var queryOverAny = buildVersionedQuery.WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(disconnected);
                return((T)(object)(queryOverAny.ToRowCountQuery().RowCount() != 0));

            case ResultFilterType.All:
                var queryOverAll     = buildVersionedQuery.WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(disconnected);
                var totalRowCount    = Helper.NhSession.QueryOver <NodeVersion>().RowCountInt64();
                var filteredRowCount = queryOverAll.ToRowCountQuery().RowCountInt64();
                return((T)(object)(filteredRowCount > 0 && filteredRowCount == totalRowCount));

            case ResultFilterType.Count:
                // The query returns a cartesian product, so get the ids and count distinct in memory.
                // Later need to switch to a "count distinct" but SqlCe doesn't support it ffs

                var countQuery = buildVersionedQuery
                                 .WithSubquery.WhereProperty(x => x.NodeVersion.Id)
                                 .In(disconnected)
                                 .Select(x => x.Id);

                countQuery.UnderlyingCriteria.SetComment("For distinct counting");

                return((T)(object)countQuery.List <Guid>().Distinct().Count());
            }

            var many = ExecuteMany <T>(query, objectBinder);

            return(many.Single());
        }
Esempio n. 3
0
        public override T PerformExecuteSingle <T>(QueryDescription query, ObjectBinder objectBinder)
        {
            var disconnected = new NhQueryOverVisitor().Visit(query.Criteria);

            var revisionStatus      = query.From.RevisionStatusType != FromClause.RevisionStatusNotSpecifiedType ? query.From.RevisionStatusType : null;
            var nodeIds             = GetNodeIds(query);
            var buildVersionedQuery = Helper.GenerateVersionedQueryPlusAttributes(nodeIds, revisionStatus: revisionStatus, limitToLatestRevision: true);

            switch (query.ResultFilter.ResultFilterType)
            {
            case ResultFilterType.Single:
            case ResultFilterType.SingleOrDefault:
                var queryOver = disconnected != null
                        ? buildVersionedQuery.WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(disconnected)
                        : buildVersionedQuery;

                var singleResults = queryOver.List().Distinct();

                singleResults = OrderMaterialisedResults(query, singleResults);

                try
                {
                    //var singleItem = queryOver.SingleOrDefault<NodeVersion>();
                    if (singleResults.Count() > 1)
                    {
                        throw new NonUniqueResultException(singleResults.Count());
                    }

                    var singleItem = singleResults.Take(1).FirstOrDefault();     // buildVersionedQuery is a cartesian product so can't tell Nh to filter in the db otherwise Nh handily caches only the first attribute value row

                    if (ReferenceEquals(singleItem, null))
                    {
                        if (query.ResultFilter.ResultFilterType == ResultFilterType.Single)
                        {
                            throw new InvalidOperationException("Sequence contains 0 elements but query specified exactly 1 must be present");
                        }
                        return(default(T));
                    }

                    return(FrameworkContext.TypeMappers.Map <T>(singleItem));
                }
                catch (NonUniqueResultException ex)
                {
                    const string nastyNhExceptionMessage     = "query did not return a unique result: ";
                    var          getNumberFromNastyNHMessage = ex.Message.Replace(nastyNhExceptionMessage, "");
                    throw new InvalidOperationException("Sequence contains {0} elements but query specified exactly 1 must be present.".InvariantFormat(getNumberFromNastyNHMessage), ex);
                }
                break;

            case ResultFilterType.First:
            case ResultFilterType.FirstOrDefault:
                var firstQuery = disconnected != null
                        ? buildVersionedQuery.WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(disconnected)
                        : buildVersionedQuery;

                var results = firstQuery.List().Distinct();

                results = OrderMaterialisedResults(query, results);

                //var firstItem = firstQuery.Take(1).SingleOrDefault<NodeVersion>();
                var firstItem = results.Take(1).FirstOrDefault();     // buildVersionedQuery is a cartesian product so can't tell Nh to filter in the db otherwise Nh handily caches only the first attribute value row

                if (ReferenceEquals(firstItem, null))
                {
                    if (query.ResultFilter.ResultFilterType == ResultFilterType.First)
                    {
                        throw new InvalidOperationException("Sequence contains 0 elements when non-null First element was required");
                    }
                    return(default(T));
                }

                return(FrameworkContext.TypeMappers.Map <T>(firstItem));

                break;

            case ResultFilterType.Last:
            case ResultFilterType.LastOrDefault:
                var lastQuery = buildVersionedQuery.WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(disconnected);
                //var firstItem = firstQuery.Take(1).SingleOrDefault<NodeVersion>();
                var lastItem = lastQuery.List().LastOrDefault();     // buildVersionedQuery is a cartesian product so can't tell Nh to filter in the db otherwise Nh handily caches only the first attribute value row

                if (ReferenceEquals(lastItem, null))
                {
                    if (query.ResultFilter.ResultFilterType == ResultFilterType.Last)
                    {
                        throw new InvalidOperationException("Sequence contains 0 elements when non-null First element was required");
                    }
                    return(default(T));
                }

                return(FrameworkContext.TypeMappers.Map <T>(lastItem));

                break;
            }

            return(ExecuteMany <T>(query, objectBinder).FirstOrDefault());
        }