Skip Navigation LinksHome / Articles / View Article

WCF RIA Services Part 3: Updating Data

+ Add to SilverlightShow Favorites
15 comments   /   posted by Brian Noyes on Jun 28, 2010
(4 votes)
Categories: Products , Tools , QuickStarts

This article is Part 3 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 2, I covered the query capabilities of WCF RIA Services in a little more depth. In this article, I’ll focus on the updating side of things, which is a bit more complicated than just retrieving data because there is a lot more going on. I’ll be covering the basic coding patterns for updating data, as well as talking about what is going on behind the scenes. Before I get to that though, there is one more important aspect of querying that I need to cover that didn’t fit in the last article, or the WCF RIA Services black helicopters will come down and get me. :)

Download the starting point for this article from Part 2 here.

Download the completed code from this article here.

IQueryable<T> and the Magic of Expression Trees

Back in Part 1, you defined a domain service method that looked like this:

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

Now if you stare straight at this method, you would probably convince yourself that it is always going to return all of the Tasks in the database every time you execute it. However, if you tilt your head to the side just right, you’ll be able to see what it really does. Go ahead, I’ll wait… See it?

OK just kidding. To understand why this does not always return all tasks, you need to understand a little about expression trees and deferred execution. When GetTasks gets called, it is not actually executing a query at all. It is just forming an expression tree and returning that as an IQueryable<T> that describes what could be returned from this method. In this case, it could potentially return all tasks in the Tasks table. The expression tree that describes that is what gets returned to the client. The execution of actually running the underlying query is deferred until some future point when you actually try to act on the collection that the expression tree represents. Whenever you see an IQueryable<T>, remind yourself that it is not necessarily a collection yet – it is an expression tree that, when evaluated, will return a collection. But that expression tree can be modified by the receiver after returning it, and that can change the results that populate the collection when it gets evaluated.

The expression tree that is sent to the client can be modified before actually executing it. For example, suppose I execute the following code on the client.

 1: TasksDomainContext context = new TasksDomainContext();
 2: taskDataGrid.ItemsSource = context.Tasks;
 3: EntityQuery<Task> query = context.GetTasksQuery();
 4: LoadOperation<Task> loadOp = context.Load(query.Where(t=>t.TaskId == 1));

In line 2, I am binding to the Tasks collection on the domain context, which is currently empty because I just constructed the domain context. Then I get an EntityQuery<Task> from the context. This still doesn’t execute anything on the server, but the EntityQuery<T> lets me shape the expression tree based on what the target server method can execute (all tasks). When I call Load on the domain context, notice that I am passing a modified expression tree that includes a Where filter to only return a single task based on its ID. If you make a modification to the query client side like this, that expression tree is sent to the server when the async load operation executes, and that expression tree is applied to the actual expression tree that executes to retrieve rows. That means that not only won’t all rows be returned from the server to the client (saving bandwidth), but they won’t even be returned from the database when the query runs through the Entity Framework ObjectContext on the server side. You can convince yourself of this by firing up SQL Profiler and look at the query that runs on the database server. It includes a where clause for the TaskId column, as specified on the client side, without needing to explicitly declare a separate method that can do the filtering itself on the server side. Is that cool or what!?

DomainContext Caching and Change Tracking

OK, with that out of the way, lets switch focus to updating data. Before I start walking through some code, its important to understand a few concepts about the way WCF RIA Services works. Behind the scenes of the domain context, there is a lot more going on that just proxying calls to the server. Any entities or collections of entities you retrieve are cached through the domain context on the client side. That is why in the code in the previous section I could just bind the data grid to the Tasks collection on the domain context before executing the query. That collection will fire change events and update the UI when the cached entities change, at the point where the async load completes. In addition to caching the entities, the domain context maintains change tracking information about the cached entities so it knows if any have been modified, deleted, or added.

So instead of explicitly calling the server every time you want to change an object, you can make a bunch of changes to a bunch of objects and those will all be cached and tracked by the domain context. Then when you want to get those changes persisted on the server, you call SubmitChanges.

Step 1: Add update methods to your domain service

In Part 1 I walked you through the wizard for adding a domain service to the web project. At that point in the interest of keeping it as simple as possible, I didn’t have you do an important step for real apps – enable editing. When you add your domain services, you should check the box next to each entity that you expect to change at all on the client side:

AddDomainService

When you check this box, the following additional methods are added to the domain service, which you can also easily add by hand:

 1: public void InsertTask(Task task)
 2: {
 3:     if ((task.EntityState != EntityState.Detached))
 4:     {
 5:         this.ObjectContext.ObjectStateManager.ChangeObjectState(task, EntityState.Added);
 6:     }
 7:     else
 8:     {
 9:         this.ObjectContext.Tasks.AddObject(task);
 10:     }
 11: }
 12:  
 13: public void UpdateTask(Task currentTask)
 14: {
 15:     this.ObjectContext.Tasks.AttachAsModified(currentTask, this.ChangeSet.GetOriginal(currentTask));
 16: }
 17:  
 18: public void DeleteTask(Task task)
 19: {
 20:     if ((task.EntityState == EntityState.Detached))
 21:     {
 22:         this.ObjectContext.Tasks.Attach(task);
 23:     }
 24:     this.ObjectContext.Tasks.DeleteObject(task);
 25: }

 

 

 

These methods are simple wrappers around the appropriate update operations on the entity framework object context.

Step 2: Add some UI to invoke an add operation

Next you need something in the UI to invoke an update or add type of operation. Again, the pattern for update, add, and delete is pretty much the same – make the modification to the collection of objects exposed by the domain context, and call SubmitChanges. To keep it simple, you can just add another couple buttons to the top of the existing MainPage.xaml. Name the two buttons addTaskButton and saveChangesButton, set their Content property to Add Task and Save Changes respectively. Add button click handlers for both as well.

AddTaskButton

 1: <Button Name="addTaskButton" Content="Add Task" Click="addTaskButton_Click" .../>
 2: <Button Name="saveChangesButton" Content="Save Changes" Click="saveChangesButton_Click" .../>

Step 3: Create a new Task, add it to the domain context, and submit changes

Add the following code to the event handlers, as well as adding a member variable to contain the domain context:

 1: TasksDomainContext context = new TasksDomainContext();
 2:  
 3: private void addTaskButton_Click(object sender, RoutedEventArgs e)
 4: {
 5:     taskDataGrid.ItemsSource = context.Tasks;
 6:     context.Load(context.GetTasksQuery());
 7:     Task newTask = new Task 
 8:     { 
 9:         TaskName = "Deploy app", 
 10:         Description = "Deploy app to all servers in data center", 
 11:         StartDate = DateTime.Today, 
 12:         EndDate = DateTime.Today + TimeSpan.FromDays(7) 
 13:     };
 14:     context.Tasks.Add(newTask);
 15: }
 16:  
 17: private void saveChangesButton_Click(object sender, RoutedEventArgs e)
 18: {
 19:     context.SubmitChanges();
 20: }

First, the code adds a member variable to the view for the domain context. As I mentioned earlier, when you are making changes to entities, you need to keep the context around long enough to submit the changes. In this case, I separated the add from the submit so you can see the effects on the client side. When you click the Add Task button, the addTaskButton_Click handler first replaces the ItemsSource for the DataGrid to replace the DomainDataSource that was hooked up in Part 1 (this is just to keep the code isolated for this article). It then calls Load again to get this domain context populated with the entities from the back end. Then it creates and populates a new Task entity and adds it to the context’s Tasks collection. That change will be seen immediately by the UI because the underlying collection implements INotifyCollectionChanged. However, the change is just cached client side, so until you call SubmitChanges, the new entity is not sent to the back end. I had you separate that out to a separate method so you can see this in the UI.

When you click Add Task, you should see the new entity show up in the DataGrid, but its TaskId is initially set to zero. After you click the Save Changes button and SubmitChanges is called, you will see the TaskId update. That is because when SubmitChanges is called, the domain context makes an asynchronous call to the server, sending only those entities that have actually changed (modified, added, or deleted). After that, if the entity is modified server side, such as setting the TaskId at the DB level, the updated entity is returned to the client and is merged with the cached copy, making it so the one in the Tasks collection is current with what the back end has. Because the entity has changed, and it implements the INotifyPropertyChanged interface, the UI updates.

DomainContext’s Async API

As mentioned in the previous parts, the Load and SubmitChanges API of the domain context execute asynchronously, meaning they don’t block the calling thread. They grab a thread from the thread pool behind the scenes, go make the calls to the server in the background, and when those calls complete, the work is automatically marshalled back to the UI thread to modify the entity collections and update the UI.

That is all smooth and effortless if all goes well. But the real world is not so perfect. You could have a connection burp, some knucklehead could have messed up the connection string, or you could have concurrency conflicts on the back end. Additionally, you may need to know when the operation completes so that you can do whatever is next in your workflow. To address these scenarios, you have two options: use the return type or hook up a callback that will be called when the operation is complete.

The first option is to work with the return value from these async methods. Load returns a LoadOperation, and SubmitChanges returns a SubmitOperation. These both derive from a common base class OperationBase, and they offer a bunch of information about the operation that you can write code against while it is running or after it is completed. They publish a Completed event when the operation completes, so you can subscribe to that to be notified when it is done. They expose any errors that happened and various other flags and properties you can check for results.

As an alternative to subscribing to the Completed event on the return value, you can instead call an overload of the Load or SubmitChanges operations that takes an Action<LoadOperation> or Action<SubmitOperation>, respectively. You pass in a callback reference and the method will be called when the operation is complete. Otherwise, the argument is the same type as the return type, so the same information is available to your code at that point.

Summary

That’s all there is to it. Make changes to the entity collection on the domain context, and call SubmitChanges. Implement methods in the domain service that take those changes and push them to storage. There is a bit more to talk about with transactions and concurrency conflicts, but I’ll have to cover those in a future episode for space considerations. Next time I’ll talk about how all this fits into the popular MVVM pattern.

Download the completed code from this article 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 3: Updating Data  

    posted by Jonx on Jun 29, 2010 04:21
    Hello,
    very nice series of articles. Clear and smooth to read and understand. Thanks.

    Now, what I don't get is how I create a parent and it's child at once? Because it run's async I'm in trouble, right?

    If for example I wanted to create a new project with some tasks already in it...
    I create a new project but have no project id until I use submit changes. That means I can add the "default" tasks only after the completed returns? Do I need to do this server side? Is the domain service InsertProject the good place to add linked items? Is this also running async? When I add some stuff in the InsertProject I have the same problem. Things are not created until after someone called SubmitChanges... I'm lost...

    Any hints on that? Thanks...
    John.
  • RE: WCF RIA Services Part 3: Updating Data  

    posted by talu on Jul 03, 2010 12:59

    Great - Thanks 

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Nen on Jul 03, 2010 15:29

    John,

    if i am correct, you dont need to submit changes twice, all you need to do is, create a Project entity and then assign the task entitties project property to the project entity created above, EF will take care of the rest.

    Example:

     Project prj=new Project();

    Taks tsk =new Task();

    tsk.Project=prj;

    context.SubmitChanges

     

     

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Brian Noyes on Jul 03, 2010 16:49

    Nen is correct. If you assign the child entity via an object reference, AND (important requirement, taken care of by Entity Framework but if not using that you would have to do yourself) decorate the parent entity properties with the Association and Include attributes, then it should all just work with a single SubmitChanges because of the change tracking information that is maintained by the DomainContext and its ability to merge the returned entities with the ones that the client side knows about.

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Sharad on Jul 07, 2010 02:58

    Thanks for this great series for beginners..i have been struggling to step into Silverlight for some time now...i come from the big fat windows world..your work is really helping me to get to grips ..i have couple of questions..i followed your part 1 and did not click on 'Enable Editing'.. for  part 2 the only way I could get the 'Enable Editing' was to delete the TaskDomainService class and recreate it again with the option checked..

    Q: Is there any other way of doing this...running any custom tool etc

    Secondly, as par part 1, I wrote the GetTasksByStartDate in the TasksDomainService class. Deleting this class meant I would loose my custom methods...This time i manage to copy and paste it again ...

    Q: Is there any way I could put my custom code in a partial class, so won't have to worry about loosing my code in future.

    Appreciate your work!


  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Brian Noyes on Jul 07, 2010 06:25

    Hi Sharad,

    Unfortunately the wizard is currently a one time opportunity, there is no way to get back into it if you don't select what you want the first time. My workaround to that is not to delete the class for the reason you mention - you might have made numerous customizations by that point and you would lose them. I just add a new domain service, say DomainService1, and select the same entities but check the edit box. You can then cut and paste the new insert/update/delete methods into the old class and delete the new one.

    You can certainly separate your domain service class into partial classes, but it won't really buy you anything since the code generation for the domain service is a one time thing.

    Hope that helps

    Brian

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Compuanalisis on Jul 09, 2010 04:20
    Many thanks for this article, it was what I was looking for.
  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Jonx on Jul 11, 2010 05:52

    Thanks to both of you for your help. Cool feature.
    Also for now, it seems to me, that the relation is working just with using the include attribute. relation does not seem to add anything to the game...

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Matt on Jul 27, 2010 01:41

    Hello Brian

    Great articles so far. Really looking forward to the next ones in the series. Thanks!

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Andy on Jul 27, 2010 20:12

    So far so good.

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by CyclingFoodmanPA on Jul 30, 2010 20:08

    Hey Brian,

    Finally, this WCF RIA stuff is starting to sink in based on your articles.  Thanks for the effort and am anxiously awaiting the rest of the series.  Have been trying to get my head around MVVM, MEF and PRISM also.

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Frank on Aug 08, 2010 16:40

    all of the tutorials i have seen link the datasource to a datagrid .. update the datagrid, and then submit changes .. is there some way you can forget the dadagrid .. link the datasource to a Inumerable collection, update the collection, and then submit the changes .. if can be done, a real simple example would be appreciated ..

    thanks for your help!

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Brian Noyes on Aug 16, 2010 14:26

    Frank,

    With RIA Services, it is just a matter of locating the item you want to work with in the entity collections managed by the domain context (i.e. Tasks in my examples so far) after having done a Load operation on the domain context, often by executing a LINQ query on the entity collection. Then modify the properties on that object and call SubmitChanges on the domain context. The entities never have to touch the UI. The code in the view model of the sample code for this article is doing exactly that. The fact that the view model happens to expose that entity collection for data binding is incidental.

  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Merrill Marie on Aug 18, 2010 00:34
    Have a stupid question, all on timing. I need data out of a data context when the page loads .. without any user intervention.
    Current process is to load data from data context then items source it to a data grid. Next step is to do a for each in the data context and creat an ienumerable. Every thing works fine, but only if I do a button click after the data grid has been item sourced. Is there some way i can do this without user intervention?
  • RE: WCF RIA Services Part 3: Updating Data  

    posted by Brian Noyes on Aug 18, 2010 00:46

    Hi Merrill,

    The data has to get into the DataContext from somewhere with some programmatic code, so you get it from there directly. In the case of RIA Services, as I described in Part 1&2, the loading of the data happens asynchronously. So even though you set the ItemsSource of an ItemsControl and/or set the DataContext to an entity collection exposed by the domain context and call Load, the entity collection does not get populated until the service call completes asynchronously. You can pass a callback delegate to the Load operation to be called when that async completion occurs, and that is your deterministic place to know when the data is there and you have programmatic access to it.

    HTH, Brian

Add Comment

 
 

   
  
  
   
Please add 4 and 1 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)