Rants Tagged with “Data”

1    (Total Pages: 1/Total Results: 6)

State of Data Access in Silverlight 4

Silverlight Logo

Back in February I wrote an article stating my opinion about the current State of Data Access in Silverlight (then Silverlight 3 and betas of WCF RIA Services and WCF Data Services). Things have improved in some ways since then but they haven't been fixed.  Here's my thoughts on the current state:

The three options for data access are still the same "Web Services, WCF Data Services and WCF RIA Services". My major issue with data access today in Silverlight persists: there is no perfect answer. There is give and take with each approach and giving good advice about the right one is difficult.  Instead of talking about the right way to do it, let's look at a chart i've been coming up with to simplify it:

 Silverlight Data Access Chart

(Click to enlarge)

This chart should represent the pros and cons I see with all the technologies.  Hopefully this helps you make the decision for your projects.

SQL Azure's OData Support

OData

I've ported my XBoxGames Database (see this blog article for copies of the .mdf files) to SQL Azure and added OData support. You can find the feed here:

https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames

While this rocks. it did expose some of the lack of full OData support in SQL Azure but they're working on them immediately.  Michael Pizzo is working on this support and send this list of what is and isn't working currently:

Supported:

Requests of the form “http://odata.sqlazurelabs.com/OData.svc/v0.1/[SQLAzureServerName]/[SQLAzureDatabaseName]” are recognized and correctly routed

  • Supports PowerPivot, Astoria Client/ASR, LinqPad, etc.

Integration with Portal, ACS

  • Impersonation based on security token for authenticated access
  • Anonymous access mapped to a particular user (read-only reference data, browser access,…)
  • Configuration information is read from a configuration table, hosted in sql azure

Metadata is dynamically loaded (changes to SqlAzure schema are immediately available through OData endpoint)

  • Pluralization support for entityset naming
  • IDs based on PKs
  • Relationships identified based on FKs
  • Goal is to generate an equivalent model to what EntityDesigner generates by default when doing modelgen from a database

The following requests are supported:

  •  ServiceDocument (/)
  •  metadata (/$metadata)
  •  entityset (/entitysetname)
  •  identity operator (/entitysetname(id))
  •  property navigation (/entityset(id)/propertyname)
  •  count (/$count)
  • single segment relationship navigation (/entityset(id)/navigationpropertyname)

The following query operators are supported:

  • $top
  • $skip
  • $orderby
  • $filter with basic expression support
  • $inlinecount
  • $select
  • $skiptoken

ServerDriven paging is supported

  • first 50 records plus NextLink

The following are supported in expressions:

  • math operators (add, subtract, multiply, divide, mod)
  • comparison expressions (equal, notequal, greaterthan, greaterthanorequal, lessthan, lessthanorequal)
  • logic expressions (AND, OR, NOT)
  • A host of string functions (length, substring, left, right, trim, replace, remove, upper, lower, startswith, endswith, concat, indexof)

Basic updating support

  • user-defined key values
  • autoincrement key values

Not supported (yet):
Stored procs
Tables/views w/no primary key
Date and Math scalar functions
EntityClient support
$expand
Many:Many relationships
Multi-level relationship navigation
Media Link Entries
Other feature requests?

Other Bugs:

Not listed in Michael's notes are a couple of other issues i've run into (but i've reported them to him so I expect they're going to be addressed soon):

Filtering along relationships:

  •  https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames/Games?$filter=Genre_1/Name eq 'Shooter'

Date Filtering:

  •  https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames/Games?$filter=ReleaseDate gt datetime'2009-12-12T12:00'

Ordering by Dates:

  •  https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames/Games?$orderby=ReleaseDate

 

WCF Data Services and jQuery

ODataI'd recently been asked by Chris Sells to help him with a simple WCF Data Services/jQuery example so I thought I'd share it via my blog as well. The basic idea is to use jQuery's AJAX functionality to retrieve JSON instead of the usual OData and consume it on a web page.

The example I decided on using is to expose the XBox database with paging. I am not doing any of the niceties like getting result counts to show a real navigation bar.  Instead this is quick and dirty to simply do "next" and "prev" and use WCF Data Service's URI API to retrieve data.

Like most of my XBox examples, I am using the Entity Framework to simply expose three entities types (Games, Genres and Ratings). Then I utilize a WCF Data Service to expose these types for consumption via REST.  My HTML is simple:

<h2>
  XBox Games</h2>
<div>
  <a href="#" id="PrevPage">Prev</a>
  <a href="#" id="NextPage">Next</a>
</div>
<div id="gameTable" />

The gameTable will simply be filled with a simple TABLE element for our data. So to the jQuery we go.  I am using plain jQuery 1.3.2 (though plugins could be used to simplify some of this code, I choose to just do it raw for simplicity).

First I set up a couple of variables to hold our paging information:

// globals for paging
var page = 0;
var pagesize = 25;

Next I handle the document's ready function to do some work when the initial page load is complete:

// Loads once the document has completed loading
$(document).ready(function () {
  
  // Set up paging buttons
  $('#PrevPage').click(function (evt) {
    // Stop the navigation from happening
    evt.preventDefault();
    if (page > 0) {
      page--;
      loadData();
    }
  });
  $('#NextPage').click(function (evt) {
    evt.preventDefault();
    page++;
    loadData();
  });
  
  // Load the initial data
  loadData();
});

When setting up the paging buttins, I use the '#PrevPage' and '#NextPage' CSS selectors to find items named PrevPage and NextPage and wire up the event to cause the page changes to happen.  The 'evt.preventDefault()' call stops the buttons from trying to navigate since we're using them as buttons.  FInally once we change the current page value, we call loadData (or in the initial case, call loadData with the default values).

function loadData() {
  var url = "/GameService.svc/Games?$orderby=Name" +
             "&$skip=" + (page * pagesize) + 
             "&$top=" + pagesize;
  $.ajax({
    type: "GET",
    url: url,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (msg) {
      loadTable(msg.d);
    }
  });
}

In the loadData function, I first create the URL by using the Data Service/OData URL API to retrieve games by Name while using the global values to retrieve a page of data at a time (see the $skip and $top parameters). Once the URL is defined, jQuery's ajax function executes the URL and returns in the success function in which we call loadTable to create the table for us. Since the returned JSON is contained in a 'd' element for security, we de-reference the 'd' element before we sent it into the loadTable function.

function loadTable(results) {
  var table = '<table><thead><tr><th>Name</th>' + 
              '<th>Publisher</th><th>Box</th></thead><tbody>';

  for (var post in results) {
    var row = '<tr>';

    row += '<td>' + results[post].Name + '</td>';
    row += '<td>' + results[post].Publisher + '</a></td>';
    row += '<td><img src="' + results[post].ImageUrl + 
           '" style="width: 100px; height=150px" /></td>';

    row += '</tr>';

    table += row;
  }

  table += '</tbody></table>';

  $('#gameTable').html(table);

}

Finally in loadTable some simple HTML construction goes on to create a table with our results.  The for loop returns a iterator for each row in the collection which we can use to retrieve the individual item (see results[post].Name as an example). Once the table is built, it replaces the contents of the element named gameTable with the new table.

Because WCF Data Services will return JSON as well, you can use it to do AJAX work just as effectively as Silverlight can consume it for rich client work.  You can get the code here:

http://wildermuth.com/downloads/DataServiceJQuery.zip

 

"Which Data Access Should I Use for Silverlight 3?"

Silverlight Logo

It all depends...

 

 

 

RIA Services, Silverlight and MVVM

Silverlight Logo

I've finally had a chance to take a look at the July CTP of RIA Services. My opinion is mixed, but its still pretty early. I ran through the simple walkthrough and it was easy to set up but it still felt as if there is too much Visual Studio magic (a complaint I've had for a long time now).

A Brief Overview

For the uninitiated let me explain a couple of things (though, please don't assume this blog entry is an introduction to RIA Services):

RIA Services is trying to share logic with the Silverlight client. That's the big story (IMHO). Some of this logic is a surface to query, validation attributes and outright code in other cases. Its trying to solve a difficult problem, but they've made a fundamental mistake in my book: RIA Services requires that all pieces are in a single solution file. But why? The magic is code generation.  

RIA Services starts with a Domain class which normally uses a model (Entity Framework or others) to expose the data.  As you change the domain class and the entities, RIA Services builds a code generated file in the Silverlight project (or other client files) for you:

The RIA Magic

As the GameDomain file and the GameModel's entities are changed, the generated code is regenerated to keep up with the changes.

Why This is Troubling

This makes sense in one case because as the domain and entities are changed, the code magically stays updated.  Which is a better experience than updating a Service Reference.  But it requires something called a RIA Link.  This link is between a client-side component (typically a Silverlight application) and a server-side component (typically an ASP.NET Web Site/Project).

The cost of this approach is that the projects must exist in the same solution file. This works for demo's and small projects, but in the big world of enterprise or Internet development this breaks down. Throw in composition strategies (like Prism solves) and it complicates it quite a lot.  I certainly hope that when it reaches 1.0 they'll have a solution for this. The current solution for this is to wrap the domain service with an ADO.NET Data Service, but that means there are two layers to go through instead of one and if that's the approach, just use ADO.NET Data Service instead, right?

Another Concern

While reading the well-written and lengthy overview on RIA Services (that comes with the RIA Services CTP) I noticed that RIA Services comes with a data source object (called DomainDataSource) that can be used directly within XAML to communicate with the domain class:

RIA Services Data Source

If you've been reading this blog for any length of time, you'll know that I think that data source objects are almost always evil in that they suggest that its ok to include data access in the user interface.  And the depth of interaction with the data source is really troubling here.

So What About RIA Services in MVVM?

My first thought was how this impact the best-practices of not co-minging UI and data.  I thought it might not work at all, but as often happens in these cases, the example isn't the exemplar that I can suggest.  The framework (aside from my concern about the solution file) actually allows this pretty easily.

So I went back and grabbed my MVVM example from my MSDN article (seen here: http://msdn.microsoft.com/en-us/magazine/dd458800.aspx) and refactored it to use RIA Services. The breakdown of that architecture was pretty simple:

MVVM Architecture

Notice I am using a RIA Domain Service on the server to expose the data model (instead of ADO.NET Data Services). This is broken up in the solution as a set of client-side projects and server-side projects:

RIA Services Project Breakdown

Notice that while in the typcial scenario (and walkthrough's) the RIA Link is betwen the Silverlight application and the web project, RIA Services allows you to have that link between separated parts of the solution. In this case, we have a MVVM.Data library that contains the entity model and the domain service class.  This allows us to re-use this in separate web projects (which is something that is harder to do in ADO.NET Data Services). We also have a MVVM.Client.Data Silverlight library that contains the model for the Silverlight application (and separates the access to the services so the client does not need to change).

The refactoring was fairly painless in that the entity types that were created with the generated code were identical to the data contract classes created by the ADO.NET Data Services - Service Reference class. I had to change the namespaces but the rest was identical.

In the model class I had to change how I was performing the queries, but the major change there was using the extension method syntax for the query instead of the LINQ syntax. The separation of the Model meant that the refactoring was simple (as the whole pattern is supposed to do).

public void GetGamesByGenre(string genre)
{
  // Get all the games ordered by release date
  var qry = Context.GetGamesQuery()
    .Where(g => g.Genre.ToLower() == genre.ToLower())     
    .OrderByDescending(g => g.ReleaseDate)
    .Take(MAX_RESULTS);

  ExecuteGameQuery(qry);
}

I do wish that the RIA Services style wasn't so RPC (Remote Procedure Call) but that may be because I see the value in client-side LINQ queries instead of "GetGamesQuery()" and such. I think the syntax could be a lot simpler.

Overall, I think that RIA Services can help solve some problems but the bottom line is still too much Visual Studio magic for my taste and the validation is still only covering the very simple cases. Rich validation is always going to be hard (read Rocky Lhotka's book if you don't believe me).

If you want to play with it, you can grab the code here:

http://wildermuth.com/downloads/MVVMExample_RIA.zip

What do you think?

Cool...I am on .NET Rocks TV (DNR-TV)

Silverlight Logo

While in Bulgaria I had time to sit down with Carl Franklin and do an episode of DNRTV.  I am happy to annouce its now live. I built a simple data-driven application using Silverlight 2 with Blend 2 and Visual Studio. This screencast should some basic techniques of separation of UI and Data in Silverlight that will help you do your data binding directly in Blend 2 SP1.  If you haven't seen how this works, go grab the Screencast now!