Skip Navigation LinksHome / Articles / View Article

WCF RIA Services Part 2: Querying Data

+ Add to SilverlightShow Favorites
12 comments   /   posted by Brian Noyes on Jun 24, 2010
(8 votes)
Categories: Products , Learn , Tutorials , QuickStarts

This article is Part 2 of the series WCF RIA Services:

  1. Getting Started with WCF RIA Services
  2. Querying Data Through WCF RIA Services
  3. Updating Data Through WCF RIA Services 
  4. WCF RIA Services and MVVM
  5. Metadata Classes and Shared Code in WCF RIA Services
  6. Validating Data with WCF RIA Services 
  7. Authenticating and Authorizing Calls in WCF RIA Services
  8. Debugging and Testing WCF RIA Services Applications
  9. Structuring WCF RIA Services Applications
  10. Exposing Additional Domain Service Endpoints for Other Clients

Overview

In Part 1, I introduced the basics of WCF RIA Services and walked you through the “hello world” equivalent for WCF RIA Services. That may have all seemed too simple, and you can’t really drag and drop your way to real world applications. For real applications, you are going to need to know more how to customize what services are exposed to the client and how to consume them on the client side. In this article, I’m going to drill down a little deeper into the process of querying data from the client. I’ll cover the conventions for query methods that you define on your domain service, as well as how to do it with configuration (attributes) instead of based on convention. I’ll show some of the programmatic ways that you can perform the queries on the client side. Finally,  I’ll talk about using data from sources other than Entity Framework.

The starting point for this article is the solution that resulted from the steps in Part 1, which you can download here.

The finished code for this article can be downloaded here.

Step 1: Add a parameterized collection query to your domain service

In the last article, I walked you through creating a domain service and after you completed the wizard, a single query method had been added to the domain service class that looked like this:

 1: public IQueryable<Task> GetTasks()
 2: {
 3:     return this.ObjectContext.Tasks;
 4: }

That query method just returned all of the tasks in the database as an IQueryable<T> and took no arguments. If you want to have more specific queries available to the client without returning all the rows, you can add specific query methods to the domain service, and they will be code generated on the client side as well. You can also choose to return an IEnumerable<T>, but if the underlying provider (i.e. Entity Framework or LINQ to SQL) returns IQueryable<T>, they you should pass that through instead as it supports more scenarios.

Say that a common use case for your application was to allow the user to retrieve tasks for a given date range. They could search for tasks before a given start date or after or between. To support that, add the following query method to your domain service:

 1: public IQueryable<Task> GetTasksByStartDate(
 2:     DateTime lowerDateTimeInclusive, 
 3:     DateTime upperDateTimeInclusive)
 4: {
 5:     return this.ObjectContext.Tasks.Where(
 6:         t => t.StartDate >= lowerDateTimeInclusive && t.StartDate <= upperDateTimeInclusive);
 7: }

 

Step 2: Add UI to execute the query

To call the search query instead of the GetTasks query that the DomainDataSource in the UI currently calls at page load, you need to add some UI. Open up MainPage.xaml and click on the DataGrid that is filling the UI. Grab the top edge and drag it down a bit to make room for a few controls. Drag and drop two TextBoxes and one Button so that it looks something like the screen shot below.

UIModification

Name the first TextBox lowerDate and the second upperDate and the button searchButton. Set the Content of the button to Search By Date. Double click on the button to add a handler.

Step 3: Execute a query on the client through the DomainContext

If you remember from the introduction in Part 1, the DomainContext is the code generated client side counterpart to the server side domain service. In this case, since the domain service is called TasksDomainService, the client counterpart is called TasksDomainContext. It exposes the ability to call the server side asynchronously and to also submit changes made to entities on the client side. The DomainContext is really the brains of the WCF RIA Services on the client side and has a lot of stuff going on internally. Whenever you retrieve entities from the server by executing a query through the domain context, the domain context also holds a reference to those objects along with some change tracking information. So if you modify those objects, it knows which have changed and can send just those entities back to the server side when you decide to submit those changes. But I’ll get into that some more in the next article. For now, lets stay focused on the retrieval side of things.

In your search button click handler, you could add the following code:

 1: private void searchButton_Click(object sender, RoutedEventArgs e)
 2: {
 3:     DateTime lowerDateVal;
 4:     DateTime upperDateVal;
 5:     GetDates(out lowerDateVal, out upperDateVal);
 6:  
 7:     TasksDomainContext context = new TasksDomainContext();
 8:     taskDataGrid.ItemsSource = context.Tasks;
 9:     EntityQuery<Task> query = context.GetTasksByStartDateQuery(lowerDateVal, upperDateVal);
 10:     LoadOperation<Task> loadOp = context.Load(query);
 11: }

The important code here are the last four lines. To call the server side, you need an instance of a domain context. In a real application, you are going to want to create an instance of the domain context that you keep around for a while, because that is where the change tracking information for submitting changes resides. So you will typically move it to a member variable in a view model or possibly an application scoped service. But I’ll get into more detail on that in Part 4 of the series.

The domain context exposes collections of entities that include the sets of collections returned by query methods on your domain service. So far the domain service just exposes a collection of Tasks. Notice that the code is replacing the ItemsSource of the DataGrid with the Tasks collection on this domain context before making any calls against it. This is because when you query through the domain context, the queries execute asynchronously and will replace the contents of the exposed collection when the query returns from the server. That collection implements INotifyCollectionChanged and will raise events that causes the DataGrid (or any data bound control) to refresh itself when those events fire.

The code then gets an EntityQuery<Task> from the context with the arguments that are passed to the corresponding domain service method. That just sets up what you want done, it doesn’t actually make a call. Finally, it gets a LoadOperation<Task> from the context by calling Load. This is the point where a call is actually made to the server, on a background thread, and automatically marshalling the changes onto the UI thread to modify the collection when the results come back.

This is the same thing that is happening under the covers on the DomainDataSource that was used in the XAML in Part 1.

The GetDates method above just extracts the dates from the TextBoxes, checking for empty strings.

Step 4: Add query methods that return a single entity

To return a single entity instead of a collection, you just define a method that does so on your domain service. A corresponding query method will show up on your domain context after compiling.

 1: public Task GetTask(int taskId)
 2: {
 3:     return this.ObjectContext.Tasks.FirstOrDefault(t => t.TaskId == taskId);
 4: }

Convention Over Configuration

This is an emerging trend in .NET development– reduce the amount of explicit configuration you need in your code and rely on some naming conventions. It may not be apparent from the domain service code so far, but it has actually been relying on convention. It is not obvious on the query side of things, because any method name will work. But for update, insert, and delete methods, there are a set of named prefixes WCF RIA Services is looking for, such as UpdateTask, InsertTask, and DeleteTask (or a number of variants for each operation).

You can also use “configuration” by decorating the methods with attributes to indicate what kind of operation it is. For the Query side, the attribute is named, not surprisingly, [Query]. Using the attribute can make your code more explicit by making it easy to recognize at a glance what kind of method it is. But the IQueryable<T>, IEnumberable<T> or Entity return type makes it pretty obvious it is a query method anyway. The one advantage of using the Query attribute is that it supports a couple of additional things, such as specifying a maximum number of results (entity count) to return even if the underlying query returns more from the database.

Custom Domain Services

What if you don’t want to use Entity Framework? Another choice is LINQ to SQL. Personally, I would recommend that if you are starting a new project, you focus on Entity Framework. It is really the most capable and likely to be long-lived data access approach for .NET now and in the future. LINQ to SQL is also supported through the separate WCF RIA Services Toolkit if you really want to use that instead.

But a lot of people are using other data access strategies (i.e. nHibernate) and other data sources (Oracle, MySQL, etc.). You can easily use those with WCF RIA Services as well, as long as you can define the data objects you want to pass as simple entities and populate those using whatever code you need to. These are referred to as POCO (Plain Old CLR Objects) domain services.

To do this, you just derive your domain service class from DomainService directly, instead of using the LinqToEntitiesDomainService base class. In the wizard when you Add > New Item > Domain Data Service, just select “empty domain service class” in the Available DataContext/ObjectContext classes drop down. Then define your own entities, return IEnumerable<T> collections of those entities for queries if your underlying data source does not support IQueryable<T>, and do whatever you need to do based on your data source in the methods.

POCODomainService

Then you would define your service in terms of your underlying data source and the entities that you are working with. The entity types you work with need to have properties that are other entities or a set of supported types that include all the built in types of the .NET framework.

The key (pun intended) thing that distinguishes your entities is that they need to have a key properties that uniquely identifies them. This is typically an int or Guid. You indicate that property with the [Key] attribute.

The code below shows a simple POCO domain service and its entity type.

 1: public class Foo
 2: {
 3:     [Key]
 4:     public int FooId { get; set; }
 5:     public string Name { get; set; }
 6: }
 7:  
 8: [EnableClientAccess()]
 9: public class MyPOCODomainService : DomainService
 10: {
 11:     public IEnumerable<Foo> GetFoos()
 12:     {
 13:         return new List<Foo> { new Foo { FooId = 42, Name = "Fred" } };
 14:     }
 15: }

 

In addition to the [Key] attribute, if you have properties on your entity that are entity types themselves (related entities or associations), then you will need to have a property along side that entity that is an ID for that entity that gets set to its key field. Additionally, on the entity property itself, you will need an [Association] attribute to indicate the ID property that sets up the relation and indicate that it is a foreign key. On the entity property, you will also need an [Include] attribute to have that related entity also retrieved when the parent entity is retrieved to the client by RIA Services. See the MSDN Library documentation for these attributes for more information.

Summary

In this article, you got a taste of how queries work with WCF RIA Services. You saw one way to query programmatically and bind to the results. You saw how to define additional query methods and learned about the conventions and configuration options for indicating your query methods in your domain service. You also learned about exposing POCO domain services. In the next article, I’ll show how to make changes to entities on the client side and get those changes made on the server.

The finished code for this article can be downloaded here.

About the Author:

Brian Noyes is Chief Architect of IDesign, a Microsoft Regional Director, and Connected System MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, DevTeach, and others. He is the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at http://briannoyes.net.

Share


Comments

Comments RSS RSS
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Rachida Dukes on Jun 24, 2010 14:58
    Thanks so much for doing these series, they're very helpful when we want to learn silverlight.
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Chuck Snyder on Jun 24, 2010 22:06

    Thanks for the work on these tutorials, really helps me get started with EF and Silverlight.

    But I do have one question (you'll probably get to it later), I need to retrieve some data from EF and work with it before displaying it on the screen.  Could you show me a simple example of walking down thru the data and processing each row??

     

    Thanks Chuck

  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Brian Noyes on Jun 29, 2010 23:12
    Chuck: see the following post: http://briannoyes.net/2010/06/29/QueryingWCFRIAServicesAndHandlingAsyncResults.aspx
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Dario on Jul 06, 2010 15:30
    Your tutorial is great! Dario from Rome, Italy
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Compuanalisis on Jul 09, 2010 04:13
    Wonderfull article, But you can drag and drop directly from the datasource into mainpage without writing any piece of code, and works perfectly.
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Rüdiger on Jul 14, 2010 10:50

    Nice article.

    Would be wonderful to make a real example for e.g. Oracle->Pocos->DataService->Context->MVVM->View with service containing functions and queries.

  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Gary G on Jul 23, 2010 20:46

    Great series, Thank you for your time and effort.

    My client side generated classes (...web.g.cs) have namespaces generated like: proj.Web.Models, Proj.Web.Views while your code has generated TaskManager and TaskManager.Web --  different code is being generated. What version of Silverlight  SDK are you using (mine is April 2010)? There appears to be some other differences as well.

  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Brian Noyes on Jul 23, 2010 22:11
    Gary, I am using the released version of the Silverlight 4 Tools for Visual Studio, which is how RIA Services shipped in May. However, I just noticed that download was updated on 7/7 so am updating my tools to that latest release.
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Gary G on Jul 24, 2010 02:50

    Great series, Thank you for your time and effort.

    My client side generated classes (...web.g.cs) have namespaces generated like: proj.Web.Models, Proj.Web.Views while your code has generated TaskManager and TaskManager.Web --  different code is being generated. What version of Silverlight  SDK are you using (mine is April 2010)? There appears to be some other differences as well.

  • RE: WCF RIA Services Part 2: Querying Data  

    posted by technette on Jul 27, 2010 19:28
    Thank you!  Once I finally got my navigation, design and connectivity going.  This is like candy because of the diversity of ways to query and display the data.
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Robin on Aug 02, 2010 14:36
    Very keen to view your next Post on MVVM and WCF RIA Services. When it is going to be posted?
  • RE: WCF RIA Services Part 2: Querying Data  

    posted by Brian Noyes on Aug 03, 2010 07:58
    Already submitted, should hit the wire any day now

Add Comment

 
 

   
  
  
   
Please add 5 and 3 and type the answer here:

Join the free SilverlightShow webcast 'Running Silverlight Outside the Browser and with Elevated Trust'. Sept 7th, 8 am - 9 am PDT.
In this live session Chris Anderson will cover configuring and debugging OOB mode, toast notifications, elevated trust, direct file access and much more.
Learn more | Register | See more webinars (hide this)