internal class StandardQueryCommand : QueryCommand { public StandardQueryCommand(IQueryCommandOptions options, IObjectMapping mapping) : base(options, mapping, true) { } public override object Execute(DirectoryConnection connection, SearchScope scope) { SearchRequest.Scope = scope; var isSorted = Options.SortingOptions != null; if (isSorted) { var sortRequest = new SortRequestControl(Options.SortingOptions.Keys) { IsCritical = false }; SearchRequest.Controls.Add(sortRequest); } return Options.PagingOptions == null ? HandleStandardRequest(isSorted, connection) : HandlePagedRequest(connection); } private object HandleStandardRequest(bool isSorted, DirectoryConnection connection) { if (isSorted) { var pageRequest = new PageResultRequestControl(LdapConfiguration.ServerMaxPageSize); SearchRequest.Controls.Add(pageRequest); } var response = connection.SendRequest(SearchRequest) as SearchResponse; AssertSuccess(response); AssertSortSuccess(response.Controls); return Options.GetEnumerator(response.Entries); } private object HandlePagedRequest(DirectoryConnection connection) { var pageRequestControl = new PageResultRequestControl(Options.PagingOptions.PageSize) { Cookie = Options.PagingOptions.NextPage }; SearchRequest.Controls.Add(pageRequestControl); var response = connection.SendRequest(SearchRequest) as SearchResponse; AssertSuccess(response); AssertSortSuccess(response.Controls); var pageResponseControl = GetControl<PageResultResponseControl>(response.Controls); var parameters = new[] { Options.PagingOptions.PageSize, pageResponseControl.Cookie, Options.GetEnumerator(response.Entries) }; return Activator.CreateInstance( typeof(LdapPage<>).MakeGenericType(Options.GetEnumeratorReturnType()), parameters); } private static void AssertSortSuccess(IEnumerable<DirectoryControl> controls) { var control = GetControl<SortResponseControl>(controls); if (control != null && control.Result != ResultCode.Success) { throw new LdapException( string.Format("Sort request returned {0}", control.Result)); } } }
Sort requests require paging or else you'll get a size limit exceeded if you have too many results. I thought this was all I needed to worry about, but when I tried to filter 50K entries I found another gem. The response of the sort request was "UnwillingToPerform". I felt like my laptop just told me to take a hike. I Googled and only turned up that something was wrong with my sort. I looked at my query and it hit me:
var orderBy = context.Query<User>() .OrderByDescending(u => u.LastName) .Select(u => new User {CommonName = u.CommonName, FirstName = u.FirstName, LastName = u.LastName}) .ToPage(50);
Basically this is the same error as size limit exceeded. Even with a page request, the filter is too broad to effectively perform a server side sort, so it fails. I applied a filter and everything worked.
Sorting is not an efficient operation for the server which is why it has a size limit. Unless you're working on a horribly constrained client, I recommend doing your sorting there.
No comments:
Post a Comment