Pixata Custom Controls
For Lightswitch

Recent Posts

Popular tags (# posts in brackets)

Anonymous types (3) ASP.NET (5) C# (3) C# tricks and tips (2) Computers (6) Design patterns (3) DomainDataSource (3) Dynamic data (4) Entity framework (3) Entity model framework (5) F# (3) LightSwitch (12) Linq (6) Microsoft (2) MVP (2) MVVM (2) Project Euler (2) RIA services (5) Silverlight (2) SQL Server (4) Unit testing (4) Visual Studio (7) WCF (3) WPF (3)

Gratuitous link to StackExchange




The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Actually, as I'm self-employed, I guess that means that any views I expressed here aren't my own. That's confusing!


Theme modified from one by Tom Watts
C#/F# code styling by Manoli (for posts pre-2016) and Google code prettify (for post from Jan 2016 and beyond)

My rambling thoughts on exploring the .NET framework and related technologies

Please note that this blog has ben retired. Most of the material has been migrated to my new blog at www.pixata.co.uk. Please update your bookmarks to point to the new blog.

I was working on a RIA service that returned information about scheduled actions. Amongst the information stored in the database table was the ID of the user who submitted (actioned) the action, the ID of the user to whom it was assigned (posh grammar eh?), and the ID of the action type. These IDs were foreign key references to other database tables.

The problem I had was that I wanted to display the information in an ASP.NET GridView, and so just wanted the name (title, first name and surname) of the two users, as well as the description of the action (from the ActionTypes table). A plain old query won't help here, as all you'll get are the IDs, not the human-readable information.

The obvious way to do this is to include the required information in the query...

   1:        var actions = from a in ObjectContext.Actions 
   2:                      select new { ByUser = a.ActionedByUser.Firstname, 
   3:                                   ToUser = a.AssignedToUser.Firstname, 
   4:                                   a.ActionType.Description };

I've only shown those three bits of information in this query, but in reality you would have other stuff in there as well.

Now this is OK, unless you want to pass the query anywhere. As I discussed in my post about passing custom and anonymous types across code boundaries, once you pass the query out of code block, you lose the type information.

In that article, we created a utility class that had just the information we wanted. Here we can't really do that, as we want the objects we handle to fit back into the RIA service, so the framework can update the database from them. If we simply create a new class, it won't have the right base type for the RIA service to handle.

The next thought was to make the utility class a subclass of the one the RIA service understood. That could be done, but was messy, mainly because we then had to modify every method in the RIA service that used the class. If we had some with the original class, and some with the subclass, we had exceptions galore.

So, we (Yossi and I, but mainly Yossi!) came up with a brilliantly simple answer. I have long been a fan of partial classes, mainly because they enable you to split class code into neat chunks, each in its own file (which probably means my classes are too big, I know). In this case, we can use the fact that the entity objects are partial classes, and simple add the required properties to them, without the need for new classes at all.

All that was needed was the following, embarrassingly simple bit of code...

   1:    public partial class Action {
   2:      public string Description { get; set; }
   3:      public string ByUser { get; set; }
   4:      public string ToUser { get; set; }
   5:    }

This added three new properties to the Action class, but still allowed the RIA service to use the class as if it hadn't been changed. Then, in the service code, we modified the query to include the required information. Two steps were needed here, first to use the Include() extension method to tell the framework to load the navigation objects that allow you to get at the foreign reference data, and second to add the actual data.

The original RIA service method call looked like this...

   1:      public IQueryable<Action> GetActions() {
   2:        return this.ObjectContext.Actions;
   3:      }

...and when we had finished, it looked like this...

   1:      public IQueryable<Action> GetActions() {
   2:        var events = this.ObjectContext.Actions
   3:                         .Include("ActionType")
   4:                         .Include("ActionedByUser")
   5:                         .Include("AssignedToUser");
   6:        foreach (Action a in events) {
   7:          a.Description = a.ActionType.Description;
   8:          a.ByUser = a.ActionedByUser.Title
   9:                     + " " + a.ActionedByUser.Firstname + " "
  10:                     + a.ActionedByUser.Surname;
  11:          a.ToUser = a.AssignedToUser.Title 
  12:                     + " " + a.AssignedToUser.Firstname 
  13:                     + " " + a.AssignedToUser.Surname;
  14:        }
  15:        return events;
  16:      }

You can see the Include() calls on lines 3-5. Having told the framework to include those navigation objects in the query (they are null by default), we then use a foreach loop to go through the query, and populate our three new properties. We are actually including the full names of the users in one field, which we couldn't have done before. Actually, we could have done it, but it would have been a bit messy. This way is pleasantly neat.

As long as the code that uses this RIA call knows about the Action type (which it would need to anyway to use the call), then it should know about the extra properties we added. This means that it can use the Action objects as normal, and take advantage of the extra information.

As with many things, once you've found the answer, it's pretty simple.

Comments are closed.