Loading data with RadDomainDataSource for Silverlight

by XAML Team | Comments 11

ddswill continue the series of blog posts about RadDomainDataSource with the most important one – the one about loading data. If you are not familiar with RadDomainDataSource then you should go back and read my introductory blog post.

Let us move straight to the data load lifecycle.

LoadingData

Triggering a Load

A load operation can be triggered in two ways. You can either call the Load method explicitly or you can rely on the AutoLoad functionality, which I will explain later in this post.

Building The Query

After a load has been requested a query based on user input is constructed on the client. This query tells the server things such as “Give me the first page of (paging) all sales employees (filtering) ordered by their sick leave hours (sorting). RadDomainDataSource will build this query based on its FilterDescriptors, SortDescriptors, PageSize and PageIndex.

If you have a Telerik control such as RadGridView, RadDataFilter, or RadDataPager that is bound to RadDomainDataSource then you don’t have to do anything since the descriptors and paging of RadDomainDataSource will be automatically updated. For example, when the user sorts RadGridView, RadGridView will “talk” to RadDomainDataSource and add a SortDescriptor to it. In fact, when two Telerik data controls detect each other they start synchronizing their descriptors automatically. They recognize each other thanks to the IQueryableCollectionView interface, but this is a topic for a separate blog post. You can use RadDomainDataSource with any other control, but it would then be your responsibility to maintain its descriptors.

To be completely correct, it is not RadDomainDataSource that builds the query, but its inner view -- the QueryableDomainServiceCollectionView, which I will call QDSCV from now on since I hate typing its name and I don’t have JustCode in Windows Live Writer. Since RadDomainDataSource is just a XAML-friendly thin wrapper over the QDSCV it simply delegates all the work to the view.

The query that is sent to server is of type EntityQuery. MSDN tells us that this class represents a query method invocation. In your client application, you can apply additional filtering on a query to limit which entities are returned. You use LINQ and a subset of LINQ query operators to modify the results returned from the query. The following lists the available query operators:

  • Where
  • OrderBy
  • ThenBy
  • Skip
  • Take

After you apply additional filtering, you pass the EntityQuery object as a parameter in the Load method of the DomainContext to execute the query and get the results.

That is exactly what the QDSCV does. It takes the original entity query, does some LINQ Expression magic to append the sorting, filtering, and paging information, and then calls the Load method of its DomainContext.

If you are doing MVVM and you are working directly with the QDSCV (i.e. you don’t have a RadDomainDataSource control), you will notice that the constructor of this class requires two things:

  1. public QueryableDomainServiceCollectionView(DomainContext domainContext
  2.     , EntityQuery<TEntity> entityQuery)
  3.     : base(domainContext, new DomainServiceCollection<TEntity>(domainContext))

The DomainContext is automatically generated for you by Visual Studio each time you build the server-side project. If the DomainService has a method called GetCustomers, then your DomainContext will have a method called GetCustomersQuery with the following signature:

  1. public EntityQuery<Customer> GetCustomersQuery()
  2. {
  3.     this.ValidateMethod("GetCustomersQuery", null);
  4.     return base.CreateQuery<Customer>("GetCustomers", null, false, true);
  5. }

So you can instantiate a new QDSCV like this:

  1. NorthwindDomainContext context = new NorthwindDomainContext();
  2. EntityQuery<Customer> query = context.GetCustomersQuery();
  3. QueryableDomainServiceCollectionView<Customer> view =
  4.     new QueryableDomainServiceCollectionView<Customer>(context, query);

If you are using the RadDomainDataSource control, you only need to specify the domain context and the name of the query as a string.

  1. <telerik:RadDomainDataSource
  2.     x:Name="customersDataSource"
  3.     QueryName="GetCustomers" PageSize="10"
  4.     LoadingData="OnCustomersDataSourceLoadingData"
  5.     LoadedData="OnCustomersDataSourceLoadedData">
  6.     <telerik:RadDomainDataSource.DomainContext>
  7.         <e:NorthwindDomainContext />
  8.     </telerik:RadDomainDataSource.DomainContext>
  9. </telerik:RadDomainDataSource>

The control will then find the appropriate method on the DomainContext by using reflection. After that it will instantiate its inner QDSCV in the same manner.

Waiting for Data

Once the query has been prepared by the QDSCV, it is time to call the Load method of the DomainContext. Before doing that however, the LoadingData event is fired. In the event handler you have a last chance to modify the EntityQuery by hand, change the LoadBehavior or cancel the whole operation altogether. If you don’t cancel the load, you exit the event handler and execution transfers to the UI thread. This is where we start waiting for the server to send some data back.

The UI thread will not block and will continue executing normally since loading data is an asynchronous process. Several properties of RadDomainDataSource (QDSCV respectively) will change to indicate that something is going on. The IsLoadingData property will evaluate to true while we are waiting for the server to return the data. Same applies for the IsBusy property. You might wonder why we have both of them. IsLoadingData is true while we are loading data, whereas IsBusy is true while we are either loading data or submitting changes. As you might have already guessed, there is a third property called IsSubmittingData. The IsBusy property is perfect for busy indicator bindings:

  1. <telerik:RadBusyIndicator IsBusy="{Binding IsBusy, ElementName=customersDataSource}">
Cancelling the Request

While you are waiting for data to return you can always call the CancelLoad method or execute the CancelLoadCommand. This will cancel the current load request. In order to test this functionality, you might want to increase the fake server delay I have placed in NorthwindDomainService:

  1. public IQueryable<Customer> GetCustomers()
  2. {
  3.     // Fake server slow-down.
  4.     Thread.Sleep(500);
  5.     return this.ObjectContext.Customers.OrderBy(c=>c.CustomerID);
  6. }
 
Receiving Data

Once the server returns the data, the QDSCV will detect this and update itself with the new entities. You don’t have to do anything special here. If you have bound your ItemsControl (for example RadGridView) to a QDSCV or RadDomainDataSource.DataView it will be automatically refreshed. This is the moment when the LoadedData event will be fired. If there was some kind of server error it will be stored in the event arguments so you can take the appropriate action.

AutoLoad

RadDomainDataSource has a property called AutoLoad. If AutoLoad is true, a load request is made each time something that affects the query changes. The changes that will trigger an auto-load include changes in the FilterDescriptors, SortDescriptors, GroupDescriptors, and QueryParameters. Furthermore, data is automatically reloaded when the PageIndex or PageSize change. Changing the page index will always load the new page of data regardless of the AutoLoad setting.

When AutoLoad is false, it is your responsibility to request a load, for example on a button click. This can be done either through the Load method or by using the LoadCommand if you are a MVVM person. Additionally, there is something called LoadDelay, but I will talk about it in one of my next blog posts.

As always, I have attached a sample project that contains all of the things that I talked about. The best way to learn what is going on under the hood would be to place breakpoints in all the methods on the client and the server and examine the local variables with the debugger.

If you have a specific question about how something works or if I couldn’t explain a concept very well – don’t hesitate to ask.

Download Sample Project


Senior Software Developer,
Telerik XAML Team

11 Comments

Jonx
Excellent post Rossen, thank you for all the details.
Looking forward for the next articles.
Jonx
Hristov, not Rossen, I guess, sorry about that ;)
Rossen Hristov
Hello John,

My name is Rossen Hristov, so it's fine :) :) :)

I am currently working on the third article. Since I am no designer and I am a newbie with MS Office Visio, it takes me twice as much to draw the diagrams than to write the text and source code. But I'll get better.

Ben
Rossen, it would be very helpful to have a separate solution done with MVVM methodology using QDSCV.

Thanks!
..Ben
Rossen Hristov
Hello Ben,

I am currently working on the MVVM Sample. I hope to get it done this year.
Ben
Rossen, are you saying that may have to wait till Next Year for the sample? :-)

Thank you and Happy New your my friend!!!
..Ben
rg
What database is using in this example? because I have AdventureWorks installed in my machine, but I don't have Customer table in there.
Thanks.
rg
What database is using in this example? because I have AdventureWorks installed in my machine, but I don't have Customer table in there.
Thanks.
Phil Short
Hi
Nice article, thanks.
I'm struggling with getting data from a SPROC. I have worked out how to do Function Imports, and generate complex types for my procedure output, but when I use the resulting "getActiveTasks" in binding to a radgrid I get no data. If I change the binding to any of my "normal" entities I get data OK. Any idea what am I missing? Or am I going to have to resort to writing code? (shiver!)
florin
can you use something similar to the microsoft dds's loadsize property? or is the loadsize == pagesize on the rdds?
what i want to ask is how can i use rdds to get only a few pages at a time from the server and scroll through those on the client. and when i reach the last page the rdds can go and get the next few pages?
Doug
I am having the exact same problem that Phil Short mentions (09 may 12). It seems there are some problems with trying to bind complex types returned from stored procedures, but I simply cannot find any clues anywhere as to how to solve this problem. Ross, can you help with either an answer or some pointers we can follow up with?
Thanks.

Comments

  1.    
      
      
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)
Read more articles by XAML Team - or - read latest articles in Developer Tools
Product Families