6

The method used right now is to check the size of the array read from DB. As long as there are other operations performed on it, such a piggy-back is fine. However, I'd like to know if there's a more direct method to query for the number of contact existing.

I'm coding in C# but JS would be to get to know too, just in case.

QueryExpression query = new QueryExpression
{
  EntityName = "contact",
  ColumnSet = new ColumnSet(true),
};
EntityCollection response = organizationService.RetrieveMultiple(query);
IEnumerable<Entity> entities = response.Entities;
Pedro Azevedo
  • 2,507
  • 1
  • 16
  • 22
  • Are you going to be so kind and show us *what* method you are using it? Description of something is never as good as the code itself. – Arran Mar 14 '13 at 09:57
  • I'm not sure why this question was closed (maybe because the users that closed it aren't familiar with Dynamics CRM 2011?). You're currently reading the count of records from the result of a Query Expression, for determining the number of Contacts. You wanted to know if there was a way to get the total count without incurring the overhead returning every single record. – Daryl Mar 18 '13 at 12:36

4 Answers4

12

Here are your options:

  1. Use QueryExpression/Linq to CRM - These methods don't support a server side count though. So this is basically what you are doing now, returning every single record to the client and then counting. The negatives for this are as follow:
    1. You get the page size, not the true number in the database.
    2. The page size is limited to 5000 records, so you'd have to implement your own logic to continue to requery until you've returned all the records
    3. Highly inefficient. All of the data from all of the entities has to be returned.
  2. oData - Technically you could use odata, but your going to have the same exact issues as QueryExpressions/Linq since it doesn't support a server side count either.
  3. Use Fetch XML - This is the only supported method of getting an aggregate count of records within CRM. It also has the advantage doing the minimum amount of work required to return the information needed.

Here is the Fetch XML and C# code required to retrieve the Count:

var xml = @"
<fetch distinct='false' mapping='logical' aggregate='true'> 
    <entity name='contact'> 
       <attribute name='contactid' alias='contact_count' aggregate='count'/> 
    </entity> 
</fetch>";

using (var service = GetOrganizationServiceProxy())
{
  var resultEntity = service.RetrieveMultiple(
  new FetchExpression(xml)).Entities.First();
  var count = resultEntity
    .GetAttributeValue<Microsoft.Xrm.Sdk.AliasedValue>("contact_count").Value;
}

Notice 50K limit!

There is a limit of 50,000 entities that can aggregated. See this SO question

If this limit is too low, you could do as the SO question suggestions, and catch the exception and just return 50,000. If you needed an exact count, probably the simple thing to do is to add a filter to limit the name to starting with a single letter, then doing 26 different queries, one for each letter. Assuming a completely uniform distribution of names (which it isn't) you should be able to get a max count of 1,300,000.


Microsoft Site explicitly stating that only Fetch XML supports the Grouping / Aggregate functions --> http://msdn.microsoft.com/en-us/library/gg334607.aspx

For CRM/CDS V9+

There is now a simple request to get the total count: https://learn.microsoft.com/en-us/dotnet/api/microsoft.crm.sdk.messages.retrievetotalrecordcountrequest?view=dynamics-general-ce-9

Daryl
  • 18,592
  • 9
  • 78
  • 145
  • 2
    @KonradViltersten I did a successful test, returning a count of 32632. – Daryl Mar 14 '13 at 13:01
  • 2
    I think you mean *uniform distribution* (i.e. every value is equally likely) and not *normal distribution* (i.e. a hump in the middle for characters *i* through *p*). I also love the pragmatic approach with 26 queries (or 26^2 if additional split would be in order for **extremely** huge data sets). – Konrad Viltersten Mar 14 '13 at 15:47
  • 1
    @KonradViltersten You are correct. I've updated it to be normal distribution. You could also do some sort of binary search method (although I'd probably split it up by more than 2) as well. For example: Try a query, if you get an exception, try a-l and m-z if a query gets an exception, split again. It would work for a non-user facing application... – Daryl Mar 14 '13 at 16:29
  • Brilliant approach. We'll get a bunch of exceptions but that's acceptable in this case. (Also - you mean in your comment that you updated to *uniform* not *normal* - the action is correct, you just mistyped. Tired?) – Konrad Viltersten Mar 14 '13 at 22:21
4

You can use the TotalRecordCount on response.

Console.WriteLine("Total number of records: " + response.TotalRecordCount);
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • 1
    Do you know if that gets the total record count for that response, or for all records in CRM? E.g. if paging is set to return 100 records at a time, but there are 5000 records in CRM, will `TotalRecordCount` return 100 or 5000? – James Wood Mar 14 '13 at 11:51
  • If paging is set to *x*, the *TotalRecordCount* is between 1 and *x*. Sadly... I assumed in my answer that OP didn't use paging because there wasn't any mentioned in his query. Now, that you mention it, I realize that he's got a superfluous comma there, so the chances are that he snippetized away the essential information aiming at creating the smallest working example illustrating his issue. – Konrad Viltersten Mar 14 '13 at 11:59
  • Well I believe CRM only returns 5000 records at a time anyway, so if that's the case I don't think `TotalRecordCount` will ever be greater than 5000. – James Wood Mar 14 '13 at 14:09
  • 1
    That's correct. That's what I meant. Let's see if the OP will complain about my suggestion (if he uses paging, as I start to suspect based on my observation). – Konrad Viltersten Mar 14 '13 at 15:15
1

You could execute FetchXML with a count aggregation.

John Rogerson
  • 553
  • 4
  • 12
  • 1
    Should do. It just executes a SQL count in the background. http://msdn.microsoft.com/en-gb/library/dd904030.aspx – John Rogerson Mar 14 '13 at 13:48
  • A slightly more up to date link :) http://msdn.microsoft.com/en-us/library/gg309565.aspx#count Along with the XrmServiceToolkit from CodePlex, you can use this approach in JS too. – John Rogerson Mar 14 '13 at 13:58
  • I'm a bit swamped this week so I can't test. Would you mind checking that you actually get something larger than, say 11k, when checking the number of instances? I've heard "somewhere" that one can't get more hits than 5k (or was it 10k) even when using fetchXml. Needs confirming. – Konrad Viltersten Mar 14 '13 at 15:17
  • +1 on the swamped front. But should be able to test something early next week. I'm confident it will be ok though. With the aggregates, there's only one 'hit', the result. – John Rogerson Mar 15 '13 at 12:29
  • Just got a return of 11,315 from one of my organisations so can confirm the 5k limit does not apply to Fetch Aggregates. – John Rogerson Mar 18 '13 at 13:50
  • just got a larger than 50k result. No funny business (other than being CRM4). 58237 – John Rogerson Mar 19 '13 at 09:32
  • Cool. Post the fetchXml and get +1 in rep. – Konrad Viltersten Mar 19 '13 at 10:30
  • Built using the Stunnware FetchXML Wizard. – John Rogerson Mar 19 '13 at 11:33
  • Darn... If I can't get it as nicely in query expressions I'm going to hear this every day from my co-workers who are stuck on the lousy fetchXml instead of using *QeryExpression* class like god intended... (Just kidding, of course, but it'd be nice to aggregate in QE, though...) – Konrad Viltersten Mar 19 '13 at 11:39
-1

I presume that you are doing some sort of select statement from your data base and looking at the returned DataTable object to see how many rows it has.

Try doing a

SELECT COUNT(*) FROM [TableName] WHERE [condition]

This will return a single number which will be the same value as the number of rows.

Jens Meinecke
  • 2,904
  • 17
  • 20
  • Sadly, no. I tagged the question with *CRM-2011* and *C#* but maybe it was too subtle. Sorry. :) –  Mar 14 '13 at 10:04
  • No, **that** part was OK. Your mistake was to tag it with C# and JavaScript. People will think it's a C#/JS related question. Which it's not (but you have to be a Dynamics person to know that). Although, where the dude got SQL from, I can't see. Rest assured, though, that everybody's trying to help you. Maybe not successfully but eagerly. – Konrad Viltersten Mar 14 '13 at 10:08
  • I like the SQL answer ;-) though, the next best thing is to do the QE with paging until there is no next page. I did this in a demo where I had 2M records and wanted to see the performance difference of querying through 50k related records. It's a crude way to do the count, but it will work. – Mike_Matthews_II Mar 14 '13 at 14:25