December 2012

Volume 27 Number 12

Data Points - Pain-Free Data Access in JavaScript--Yes, JavaScript

By Julie Lerman | December 2012

Julie LermanAlthough I think of myself as a plumber when it comes to software development, I have to do a fair amount of client-side development as well. Even in this column, I venture into client apps where they intersect with data access. But when the client side is JavaScript, it’s never been pretty—my JavaScript skills, unfortunately, are still lacking and each learning curve is a world of pain for me (and for my Twitter followers, who are subjected to my venting). But it’s always worth it when I push through the brick wall and get to success. And anything that makes working in JavaScript easier for me is something I welcome with open arms. So when, during a Vermont.NET User Group presentation on single-page applications, Ward Bell from IdeaBlade, gave us a look at an open source data access API for JavaScript that he and his team were cooking up, I was very interested. From the perspective of my experience with the Entity Framework, what I saw was comparable to using EF for client-side Web development. The API is called Breeze and at the time of this writing is in beta. Bell was generous with his time to help me learn more about Breeze for the sake of this column. You can get it at breezejs.com, where you’ll also find an impressive array of documentation, videos and samples.

My June 2012 Data Points column, “Data Bind OData in Web Apps with Knockout.js” (msdn.microsoft.com/magazine/jj133816), focused on using Knockout.js to more easily perform data binding on the client side. Breeze works seamlessly with Knockout, so I’m going to revisit the example from the June column. My goal is to see how introducing Breeze could simplify my coding effort in the example’s workflow:

  • Getting data from the server.
  • Binding and presenting that data.
  • Pushing changes back to the server.

I’ll walk through the critical parts of an updated solution so you can see how the puzzle pieces fit together. If you want to follow along with a properly set-up solution and test things out, you can download the full solution from msdn.com/magazine/msdnmag1212.

The Original Sample

Here are the key steps of my earlier solution:

  • On the client side, I defined a person class that Knockout can use for data binding:
function PersonViewModel(model) {
  model = model || {};
  var self = this;
  self.FirstName = ko.observable(model.Name || ' ');
  self.LastName = ko.observable(model.Name || ' ');
}
  • My data was provided via an OData data service, so I accessed the data using datajs, a toolkit for consuming OData from JavaScript.
  • I took the query results (which are returned as JSON) and created a PersonViewModel instance with the values.
  • My app then let Knockout handle the data binding, which also coordinates changes made by the user.
  • I took the modified PersonViewModel instance and updated my JSON object from its values.
  • Finally, I passed the JSON object to datajs to save back to the server through OData.

I didn’t even bother with related data, as it would have added a lot more complexity for that small sample.

An Updated Service Using ASP.NET Web API

With Breeze, I can make HTTP calls to my OData service or to a service defined by ASP.NET Web API (asp.net/web-api). I switched my service to ASP.NET Web API, which works against the same EF model I used previously—with one addition. My former sample exposed only Person data. I now have related data in the form of a Device class, as every developer I know has a small collection of personal devices. The relevant functions exposed by my ASP.NET Web API are a GET, which returns Person data; another GET for Device data; and a single POST for saving changes. I’m also using a Metadata function to expose the schema of my data, as shown in Figure 1. Breeze will use this Metadata in order to understand my model.

Figure 1 Key Ingredients of My Web API Service

readonly EFContextProvider<PersonModelContext> _contextProvider =
  new EFContextProvider<PersonModelContext>();
[AcceptVerbs("GET")]
public IQueryable<Person> People()
{
  return _contextProvider.Context.People;
}
[AcceptVerbs("GET")]
public IQueryable<Device> Devices()
{
  return _contextProvider.Context.Devices;
}
[AcceptVerbs("POST")]
public SaveResult SaveChanges(JObject saveBundle)
{
  return _contextProvider.SaveChanges(saveBundle);
}
[AcceptVerbs("GET")]
public string Metadata()
{
  return _contextProvider.Metadata();
}

Breeze.NET on the Server

Take note of the _contextProvider variable used in these methods. I’m not calling methods of my EF DbContext (PersonModelContext) directly. Instead, I’ve wrapped it with the Breeze EFContextProvider. This is where the _contextProvider.Metadata method is coming from, as well as the signature of SaveChanges, which accepts a saveBundle parameter. With saveBundle, Breeze is going to let me send a set of data modifications from my app, which it will pass on to my DbContext to persist to the database.

I’ve named my ASP.NET Web API app “BreezyDevices,” so now I can request schema using https://localhost:19428/api/breezydevices/metadata. And I can query for data by specifying one of the GET methods: https://localhost:19428/api/breezydevices/people.

Because Breeze on the client side will query and save to an ASP.NET Web API remote service, I can remove datajs from my client app.

How Breeze Will Help My Sample

In the scope of this sample, I’ll use Breeze to focus on three pain points:

  1. My service returns and accepts bare JSON, but I need to work with JavaScript objects with Knockout observable properties for data binding to the UI.
  2. I want to include related data, but this is hard on the client.
  3. I need to send multiple changes to the server for saving.

With Breeze, I can data bind directly to my resulting data. I’ll configure Breeze to use Knockout and, in response, it will create Knockout observable properties for me under the covers. This means that working with related data is much simpler because I don’t have to translate it from JSON to bindable objects, and I don’t have to make the extra effort to redefine graphs on the client side using my query results.

There is some server-side configuration involved in using Breeze. I’ll leave the details of that to the Breeze documentation so I can focus on the client-side data-access part of the sample. And because there’s a lot more to Breeze than what I’ll be leveraging in this sample, once I’ve given you the flavor of it you’ll want to visit breezejs.com to learn more.

Figure 2 shows where Breeze fits into the workflow on the server side and on the client side.

The Breeze.NET API Helps on the Server While the BreezeJS API Helps on the Client
Figure 2 The Breeze.NET API Helps on the Server While the BreezeJS API Helps on the Client

Querying from Breeze

My experience with OData and with Entity Framework makes querying with Breeze familiar. I’ll work with the Breeze EntityManager class. The EntityManager is able to read the data model supplied by your service’s metadata and produce JavaScript “entity” objects on its own; you don’t have to define entity classes or write mappers.

There’s a bit of client-side configuration to do as well. For example, the following code snippet creates shortcuts to some Breeze namespaces and then configures Breeze to use Knockout and ASP.NET Web API:

var core = breeze.core,
           entityModel = breeze.entityModel;
core.config.setProperties({
  trackingImplementation: entityModel.entityTracking_ko,
  remoteAccessImplementation: entityModel.remoteAccess_webApi
});

It’s possible to configure Breeze to use a number of alternative binding frameworks (such as Backbone.js or Windows Library for JavaScript) and data-access technologies (such as OData).

Next, I create an EntityManager that knows the relative uri of my service. The EntityManager is comparable to an Entity Framework or OData context. It acts as my gateway to Breeze and caches data:

var  manager = new entityModel.EntityManager('api/breezydevices');

Now I can define a query and have my EntityManager execute it for me. This code is not too dissimilar to using Entity Framework and LINQ to Entities, or to working with any of the OData client APIs, so it was my favorite part of learning how to use Breeze:

function getAllPersons(peopleArray) {
    var query = new entityModel.EntityQuery()
      .from("People")
      .orderBy("FirstName, LastName");
    return manager
      .executeQuery(query)
      .then(function (data) {
        processResults(data,peopleArray); })
      .fail(queryFailed);
  };

I’m doing this on the client side and can perform my query execution asynchronously, which is why the executeQuery method lets me define what to do when the query executes successfully (.then) as well as what to do if it fails (.fail).

Notice that I’m passing an array (which you’ll see shortly is a Knockout observable array) to getAllPersons. If the query execution succeeds, I pass that array on to the processResults method, which will empty the array and then populate it with the data from the service. Previously I would’ve had to iterate through the results and create each PersonViewModel instance myself. Using Breeze, I can use that returned data directly:

function processResults(data, peopleArray) {
    var persons = data.results;
    peopleArray.removeAll();
    persons.forEach(function (person) {
      peopleArray.push(person);
    });
  }

This gives me an array of person objects that I’ll present in the view.

The getAllPersons function is inside of an object I’ve called dataservice. I’ll use dataservice in the next bit of code.

A Self-Populating View Model

In the sample from my June Knockout article, the query and results were separate from the PersonViewModel class I used for the data binding in the view. So I executed the query and translated the results into a PersonViewModel instance with mapping code that I wrote. As I don’t need mapping code or a PersonViewModel with Breeze, I’ll make my app a bit smarter this time and have it display an array of Person objects fetched from the database by my dataservice. To reflect this, I now have an object named PeopleViewModel. This exposes a people property that I’ve defined as a Knockout observable array, which I populate using dataservice.getAllPersons:

(function (root) {
  var app = root.app;
  var dataservice = app.dataservice;
  var vm = {
    people: ko.observableArray([]),
    }
  };
  dataservice.getAllPersons(vm.people);
  app.peopleViewModel = vm;
}(window));

In the download sample you’ll find a file called main.js, which is the starting point for the application logic. It contains the following line of code that calls the Knockout applyBindings method:

ko.applyBindings(app.peopleViewModel, $("content").get(0));

The applyBindings method connects the view model properties and methods to the HTML UI controls via the data bindings declared in the view.

The view in this case is a small chunk of HTML in my index.cshtml. Notice the Knockout data-bind markup that binds and displays the first and last name of each person object in the people array:

<ul data-bind="foreach: people">
  <li class="person" >
    <label data-bind="text: FirstName"></label>
    <label data-bind="text: LastName"></label>
  </li>
</ul>

When I run my app I get a read-only view of my person data, as shown in Figure 3.

Using Breeze and Knockout to Easily Consume Data in JavaScript
Figure 3 Using Breeze and Knockout to Easily Consume Data in JavaScript

Tweaking JavaScript and Knockout to Allow Editing

As you may recall from the June column, Knockout makes it easy to bind data for editing. Together with Breeze, this is a great combination for easily editing data and persisting it back to the server.

First, I add a function to the dataservice object that calls the Breeze manager.saveChanges method. When called, the Breeze EntityManager bundles up the pending changes and POSTs them to the Web API service:

function saveChanges() {
     manager.saveChanges();
  }

Then I’ll expose the new saveChanges function as a feature of the dataservice:

var dataservice = {
    getAllPersons: getAllPersons,
    saveChanges: saveChanges,
  };

Now my PeopleViewModel object needs to expose its own save method for binding to the view; the view model save function delegates to the dataservice saveChanges method. Here I use a JavaScript “anonymous function” to define the view model save:

var vm = {
    people: ko.observableArray([]),
    save: function () {
      dataservice.saveChanges();
    },
  };

Next, I replace my labels with input elements (text boxes) so the user can edit the Person objects. I have to switch from “text” to the Knockout “value” keyword to enable two-way binding to user input. I also add an image with a click event bound to the PeopleViewModel.save method:

<img src="../../Images/save.png" 
  data-bind="click: save" title="Save Changes" />
<ul data-bind="foreach: people">
  <li class="person" >
    <form>
      <label>First: </label><input 
        data-bind="value: FirstName" />
      <label>Last: </label> <input 
        data-bind="value: LastName" />
    </form>
  </li>
</ul>

That’s it. Breeze and Knockout will take care of the rest! You can see the data displayed for editing in Figure 4.

Using Breeze to Save Data via JavaScript
Figure 4 Using Breeze to Save Data via JavaScript

I can edit any or all of these fields and click the save button. The Breeze EntityManager will gather up all of the data changes and push them up to the server, which in turn will send them to Entity Framework to update the database. While I won’t be extending this demo to include inserts and deletes, Breeze can certainly handle those modifications as well.

This is the part of any JavaScript application that many developers dread—and it’s exactly the reason I wanted to write this column.

I’ll make one small change to my script and add a little markup to the form that will turn each person into an editable master/­detail person.

The change in my script will be in dataservice, where I’ll modify the query by adding in the Breeze expand query method to eager-­load each person’s devices along with the person. Expand is a term you might recognize from OData or NHibernate, and is similar to Include in the Entity Framework (Breeze also has support to easily load related data after the fact):

var query = new entityModel.EntityQuery()
           .from("People")
           .expand("Devices")
           .orderBy("FirstName, LastName");

I’ll then modify my view so that it knows how to display the Device data, as shown in Figure 5.

Figure 5 Modifying the View to Display the Device Data

<ul data-bind="foreach: people">
  <li class="person" >
    <form>
      <label>First: </label><input 
        data-bind="value: FirstName" />
      <label>Last: </label> <input 
        data-bind="value: LastName" />
      <br/>
      <label>Devices: </label>
      <ul class="device" data-bind="foreach: Devices">
        <li>
          <input data-bind="value: DeviceName"/>
        </li>
      </ul>                     
    </form>
  </li>
</ul>

And there you have it. As you can see in Figure 6, Breeze handles the eager loading and building of the graphs on the client side. It also coordinates the data to be sent back to the service for updates. On the server side, the Breeze EFContextProvider sorts out all of the change data that it receives and makes sure that the Entity Framework gets what it needs to persist the data to the database.

Consuming and Saving Related Data
Figure 6 Consuming and Saving Related Data

While this was simple with a one-to-many relationship, at the time of this writing the beta version of Breeze doesn’t support many-to-many relationships.

Pain-Free Client-Side Data Access

Bell tells me it was his own painful experience of working on a project that was both JavaScript-intensive and data-access-intensive that inspired Breeze. His company, IdeaBlade, has always focused on creating solutions to solve the problems of handling disconnected data, and the developers were able to bring a great deal of experience to this open source project. I’ve always been reluctant to embark on projects that use a lot of JavaScript because my skills are lame to begin with, and I know the data-access bits would make me unhappy. I was very interested in Breeze as soon as I saw it. And though I’ve only scratched its surface, the last bit of what I showed you in this article—how easy it was to consume and save related data—is what really won me over.


Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other Microsoft .NET topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of “Programming Entity Framework” (2010) as well as a Code First edition (2011) and a DbContext edition (2012), all from O’Reilly Media. Follow her on Twitter at twitter.com/julielerman.

Thanks to the following technical expert for reviewing this article: Ward Bell