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>()); }
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()); }
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()); }