Entities , How many ways do I count thee ?
Its a common ask that we introduce aggregating mechanisms in Data services so that one can do a Count of
the number of entities present in an EntitySet easily.
In this blog post , I will outline one method of implementing a “Count” method that works for you.
The interface to the count method will be
https://<ServiceEndPoint>/Count?entitySetName='<entitySetName>'
Server-Side
On the server-side , we will write a Service Operation that takes the name of the EntitySet as an input parameter.
[WebGet]
public long Count(string entitySetName) {
//Implementation goes here
}
In your Service Operations / Interceptors , you have access to the CurrentDataSource which represents your data providers.
The entity sets are properties off of the CurrentDataSource. We will get the entityset off of the CurrentDataSource
and get the count of entities by casting it to IListSource.
[WebGet]
public long Count(string entitySetName) {
long countOfEntities = 0;
//Get the Property off of the CurrentDataSource
PropertyInfo esProperty = this.CurrentDataSource.GetType().GetProperty(entitySetName);
//Get the EntitySet off of the CurrentDataSource
object esValue = esProperty.GetValue(this.CurrentDataSource, null);
//Cast the EntitySet to IListSource
IListSource genericESList = esValue as IListSource;
//Get the count of entities by fetching the list and getting the value of its "Count" Property
countOfEntities = genericESList.GetList().Count;
return countOfEntities;
}
Client-Side
we will make an extension method on the data service context that takes the name of the entityset and returns the count.
DataServiceContext nwContext = new DataServiceContext( new Uri("ServiceRoot") );
long countOfProducts = nwContext.Count("Products");
Extension method on the DataServiceContext to retrieve count of entities in entityset on the server .
public static long Count(this DataServiceContext context, string entitySetName) {
//Call the ServiceOperation on the server side passing the entitySetNameas a parameter
var results = context.Execute<long>(new Uri(String.Format("Count?entitySetName='{0}'", entitySetName),
UriKind.RelativeOrAbsolute));
//Get the result off of the IEnumerable
long count = results.First<long>();
//return the count
return count;
}
Complete Sample Code :
Put this in your Service Code on the server .
[WebGet]
[SingleResult]
public long Count(string entitySetName) {
long countOfEntities = 0;
if (entitySetName == null) {
throw new ArgumentNullException("entitySetName");
}
//Get the Property off of the CurrentDataSource
PropertyInfo esProperty = this.CurrentDataSource.GetType().GetProperty(entitySetName);
if (esProperty == null) {
throw new ArgumentException(String.Format("No EntitySet named {0} found on the DataSource", entitySetName));
}
try {
//Get the EntitySet off of the CurrentDataSource
object esValue = esProperty.GetValue(this.CurrentDataSource, null);
//Cast the entitySet to IListSource
IListSource genericESList = esValue as IListSource;
//If the cast succeeded
if (genericESList != null) {
countOfEntities = genericESList.GetList().Count;
}
}
catch (Exception exception) {
throw new DataServiceException("'Count' method Failed with , see InnerException -->", exception);
}
return countOfEntities;
}
Put this in your client Code .
public static class ClientExtensions {
/// <summary>
/// This Method returns the count of the number if entities present in an Entityset
/// </summary>
/// <param name="context">The DataServiceContext which contains the entities</param>
/// <param name="entitySetName">The EntitySetName whose entities should be counted</param>
/// <returns>The number of entities in the entityset</returns>
/// <example>
/// long countOfProducts = context.Count("Products");
/// </example>
public static long Count(this DataServiceContext context, string entitySetName)
{
//Call the ServiceOperation on the server side passing the entitySetName as a parameter
var results = context.Execute<long>(
new Uri(String.Format("Count?entitySetName='{0}'", entitySetName), UriKind.RelativeOrAbsolute)
);
//Get the result off of the IEnumerable
long count = results.First<long>();
//return the count
return count;
}
}
In a future post , I will talk about how to off load the counting work to your database , if you have a relational database
as your backend.
Comments
Anonymous
August 17, 2008
PingBack from http://informationsfunnywallpaper.cn/?p=954Anonymous
August 18, 2008
Great solution if all you want is the complete count of an entityset. But by not implementing the 'Count()' method of IQueriable in DataServices we are going to be very limited in uses for this technology. The benefits of using paging or virtual lists will be diminished because you will need to return all the results to the client to count the possible rows and discard the rows not visible in the current view.Anonymous
August 19, 2008
The comment has been removedAnonymous
August 25, 2008
The comment has been removedAnonymous
September 03, 2008
Hi, what JB (my initials are the same, btw) probably means: How would you calculate how many pages to show when doing pagination AND filtering. Just a simple "Displaying page 1 of 20 (filtered)" message. Same with virtual lists, you need the row count of your query to get the scrollbar right.Anonymous
September 03, 2008
Jabe, Thanks for clarifying that . If you are dealing with virtual rows , then there should be some actual data in the store for the same. Retrieving a count for the virtual rows in this way without downloading all the rows would be easy if you can offload the counting of the rows to the DataProvider. When dealing with Sql Server , you can write a stored procedure and call it from the Service Operation . or when dealing with a CLR backed data source , you can have a method on the data provider which can be accessed in the ServiceOperation via the this.CurrentDataSource property and return the virtual count for the entity set . I would think that this would be easy to implement and gives you a lot of flexibility in customizing your counting logic. Does that help ?Anonymous
September 03, 2008
Hi, thanks for your answer. In my case I'm using ExtJS to query my REST interface. Now, ExtJS more or less expects a total property in the JSON response. So the perfect solution for my problem would be to extend the returned JSON object and add a count. However I am not sure if thats even possible.Anonymous
October 06, 2008
The comment has been removed