Include count of linked records in OData result - asp.net-mvc-4

I've got a table "Events" with a linked table "Registrations", and I want to create an OData service that returns records from the Events table, plus the number of registrations for each event. The data will be consumed client-side in JavaScript, so I want to keep the size of the returned data down and not include all linked registration records completely.
For example:
ID Title Date Regs
1 Breakfast 01.01.01 12:00 4
2 Party 01.01.01 20:00 20
I'm building the service with ASP.NET MVC4. The tables are in an MSSQL database. I am really just getting started with OData and LINQ.
I tried using the WebAPI OData system first (using classes of EntitySetController) but was getting cryptic server errors as soon as I included the Registrations table in the entity set. ("The complex type 'Models.Registration' refers to the entity type 'Models.Event' through the property 'Event'.")
I had more success building a WCF OData system, and can request event information and information on related registrations.
However, I have no clue how to include the aggregate count information in the event result set. Do I need to create a custom entity set that will be the source for the OData service? I probably included too litte information here for finding a solution, but I don't really know where to look. Can somebody help me?

If you're willing to make an extra request per Event, you could query http://.../YourService.svc/Events(<key>)/Registrations/$count (or http://.../YourService.svc/Events(<key>)/$links/Registrations?$inlinecount=allpages if you're also using the links to the Registration entities).
Examples of both of these approaches on a public service:
http://services.odata.org/V3/OData/OData.svc/Suppliers(0)/Products/$count
http://services.odata.org/V3/OData/OData.svc/Suppliers(0)/$links/Products?$inlinecount=allpages&$format=json
I'm guessing that you'd prefer this information to come bundled together with the rest of the Events response though. It's not ideal, but you could issue a query along these lines:
http://services.odata.org/V3/OData/OData.svc/Suppliers?$format=json&$expand=Products&$select=Products/ID,*
I'm expanding Products (analogous to your Registrations) and selecting Products/ID in order to force the response to include an array that is the same size as the nested Products collection. I don't care about ID -- I just chose a piece of data that would be small. With this JSON response, your javascript client can get the length of the Products array and use that as the number of Products that are linked to the given Supplier.
(Note: to have your service support $select queries using WCF Data Services, you'll need to include this line when you initialize the service: config.DataServiceBehavior.AcceptProjectionRequests = true;)
Edit to add: The approach using $expand and $select won't be guaranteed to give you the correct count if your server does server-driving paging. In general, there isn't a simple single-response way to do what you're asking for in OData v3, but in OData v4, this will be possible with the new expand/select syntax.

i'm using oData v4 and i used this syntax :
var url = '.../odata/clients?$expand=Orders($count=true)';
// ...
a field called Orders#odata.count has been added to the response entity which contains the correct count.
and now to access the JSON property containing a dash you have to do it like this :
var ordersCount = response.value['Orders#odata.count'];
hope this helps.

Can you edit your Event model and add a RegistrationCount property? That'd be the simplest way I think

What I ended up doing was actually very simple; I created a View in SQL Server that returns the table including the registration counts. Never thought about using a view, since I've never used them before...

I used this to get the child count without returning the entities:
/Parents$expand=Children($count=true;$top=0)

Related

getAllContentServices returns Huge Data

I am using Yodlee “getAllContentServices” API to get all content services. But service returns a
huge amount of data (More Than 26 MBs) and returns more than 12k records, which is very difficult
to handle in a single service call, Is it any other way exist to access this service page wise.
Thanks
There are two options to do this -
call getAllContentServices and pass "notrim=false" and then for each contentService ID you can call - getContentServiceInfo1 with desired reqSpecifier to get the information.
OR
Use getContentServicesByContainerType2 and get the list of content services based on the container type.

Create Salesforce Case object with nested relationships using REST API

I am attempting to create a new Case object using the REST API but need to find out how to format the JSON body to pass in nested SObjects.
It's not apparent in the Docs, and I can't seem to find any examples. Anyone have any pointers or have done this before?
The SF web UI uses a text lookup field to set the (related) Contact and Account, and I need to figure out how to either bypass the need for a lookup or embed the SObjects of the related records in the JSON.
[{"message":"The value provided for foreign key reference Contact is not a nested SObject","errorCode":"INVALID_FIELD"}]
Figured it out by simply setting the AccountId and ContactId attributes on the new Case object.
I also haven't seen any documentation about this, but if you look at the object metadata returned by the REST API for any standard object, it seems that the suffix 'Id' is appended to any field of type "reference". For example, Case has OwnerId, LastModifiedById, CreatedById, etc. This suffix is not present in the field names displayed in the browser interface. The WSDL for the SOAP API includes both the ID as a simple element of type "ID", as well as a complex child element for nesting the actual record.

How to not get related data in Entity Framework

I have the following scenario.
I have one table in the database A that contains a lot of entries. This table is lightweight and only have a bit of data for each entry.
Another table B has a many to one relationship with A, and can contain lots of data.
I have a client and a server in my application that communicates using WCF.
My problem is that when the client calls a method on the server that should return all the A's, I get much more data than I need to. On the server I basically have a single line of code:
return entityContext.A.ToList();
My problem is that on the client, if I debug and inspect the returned collection, each element has the property B populated with all the data from the expensive table.
I only needed the basic data from the A table to show a list on the client, but ended up sending a ton of data over the wire.
So the question is, how can I make the server ignore the B table when I fetch the data to send to the client. Basically, I need something like the oposite of Include.
You need to turn off lazy loading. It can be done either through designer or in code by calling:
entityContext.ContextOptions.LazyLoadingEnabled = false;

WCF data services - Limiting related objects returned based on critera

I have an object graph consisting of a base employee object, and a set of related message objects.
I am able to return the employee objects based on search criteria on the employee properties (eg team) etc. However, if I expand on the messages, I get the full collection of messages back. I would like to be able to either take the top n messages (i.e. restrict to 10 most recent) or ideally use a date range on the message objects to limit how many are brought back.
So far I have not been able to figure out a way of doing this:
I get an error if I attempt to filter on properties on the message (&$filter=employee/message/StartDate gives an error ">No property 'StartDate' exists in type 'System.Data.Objects.DataClasses.EntityCollection`1).
Attempting to use Top on the message related object doesn't work either.
I have also tried using a WebGet extension that takes a string list of employee IDs. That works until the list gets too long, and then fails due to the URL getting too long (it might be possible to setup a paging mechanism on this approach)...
Unfortunately the UI control I am using requires the data to be in a fairly specific hierarchical shape, so I can't easily come at this from starting on the message side and working backwards.
Outside of making multiple calls does anyone know of a method to accomplish this with wcf data services?
Thanks!
M.
Looks like the only real way of doing this is in fact to reverse the direction of the query.
So instead of starting from the Employee, I go from the message side. You can filter back on the employee properties, and restrict on the Messages collection. Its not ideal, as it means iterating the collection on return to re-center it on the employee for what I am attempting to do, but it will work. The async nature of silverlight and rich client at least means while an extra iteration is required, it still appears to be reasonably fast.
Another interesting thing to note: the current version of odata/wcf data services does not support querying on properties of inherited classes, so I had to move the start/end date properties up to the base class in order to be able to restrict my search on them.
http://Site/Service.svc/Messages()?&$filter=Employee/OfficeName eq 'Toronto' and (year(StartDate) eq 2010 and month(StartDate) ge 9 )

How can I use expand() to include multiple levels of eager loaded properties for an entity with WCF Data Services for Silverlight?

I'm using Silverlight 4.0 (so I need to make the call async and can't use EF directly) with a WCF Data Service and EF 4 to model the database.I want to make one call and have several levels of properties populated.
Say I have the following setup (but this could go deeper):
Accounts
-- has zero or more Customers (and other properties)
-- Customer has zero or more Addresses (and other properties)
I want to bring back 1 payload where Accounts, Customers, and Addresses are all eager loading and included in that one payload.
I want to get : Accounts.Expand("Customers").Where(a => a.Id == 1); This returns the payload with the account and customer populated. How do I include the Addresses in the same call?
Just add Expand("Customers/Addresses"), you can add more of these, although there's a limit usually on the server. Something like 10 expanded entities should work, more might be problematic.