UPDATE: I recently published a WintellectNow course (Getting Started with Breeze.js) that goes into more depth using Breeze in the context of an AngularJS app. Use code NSTIEGLITZ-13 for a free 2 week WintellectNow trial.
- Rich “LINQ like” Querying
- Change Tracking
- Entity Relationship Navigation
- Client Caching
- Offline Saving
- Tight Integration with Web API and Entity Framework (neither are required)
- Access to any RESTful API using custom metadata
In future posts I will expand on the entire feature set. In this post, I’ll focus on the Rich “LINQ like” Querying.
LINQ like Querying
Advanced querying is probably the most compelling case for BreezeJS. If you’re familiar with Entity Framework, querying in BreezeJS will feel quite intuitive. With Breeze, you can easily write queries that filter, sort, page, project data, and even eager load relationships.
Here is a simple query that filters a list of customers by Company Name:
var query = breeze.EntityQuery.from('Customers') .where('CompanyName', FilterQueryOp.Contain, 'Around');
It is also possible to build up queries by chaining predicates. This is useful, for example, if you have a search page with many optional search parameters. In this example, I chain two predicates using and:
var query = breeze.EntityQuery.from('Customers'); var p1 = breeze.Predicate.create('ContactTitle', 'Contains', 'Rep'); var p2 = breeze.Predicate.create('City', 'Eq', 'London'); var pred = breeze.Predicate.and([p1, p2]); query = query.where(pred);
I’ve used the predicate technique before with Entity Framework on the service tier; I’m glad to see a similar technique on the client.
Just to show you what’s possible, below is an example of a pretty advanced query. It retrieves a list of all customers who have placed any orders with order details that have a quantity greater than 40:
var query = breeze.EntityQuery .from('Customers') .where('Orders', 'any', 'OrderDetails', 'all', 'Quantity', '>', 40);
As seem, it’s easy to filter deep into the object graph.
Now you have seen how to build a query, here is how you execute a query:
manager.executeQuery(query) .then(successCalllback) .fail(failCallback) .fin(finallyCallback); //execute the query and resolve to a promise
When you call executeQuery(query), Breeze will:
- Generate a URL which looks something like this:
- http://localhost:50283/breeze/Customer/Customers?$filter=Orders/any(x1: x1/OrderDetails/all(x2: x2/Quantity gt 40)
- Notice the where clause from the query has been converted into the URLs query string (a la ODATA).
- Asynchronously issues an HTTP GET to the server and expects a JSON payload in the returned HTTP response body
- Assuming the call was a success, Breeze reshapes the JSON data into Breeze entities and merges those entities into the local cache. It then resolve the promise, allowing you, the developer, to handle the returned data via the successCallback.
Thanks Breeze – that was awesome! Now in the successCallback I can bind the data to a view, log any errors in my failCallback, and do any cleanup in the fin callback.
Sorting in BreezeJS is super straight forward and pretty powerful. Check out this example from the BreezeJS documentation:
// Products sorted by their Category names, then by Product name (in descending order) var query = breeze.EntityQuery.from('Products') .orderBy('Category.CategoryName, ProductName desc');
The code is pretty self explanatory. It demonstrates that you can sort by related properties either ascending or descending. As an alternative to adding the desc text, there is also an orderByDesc method.
// Products in descending name order (version 2) var query = breeze.EntityQuery.from('Products') .orderByDesc('ProductName');
Breeze provides the ability to page data using the skip and take methods as demonstrated in this query:
// Get the 3rd page of 5 Customers // by skipping 10 Customers and taking the next 5 var query = breeze.EntityQuery.from('Customers') .orderBy('ContactName') .skip(10) .take(5);
If you don’t need all properties on an entity, you can use projection to retrieve only the relevant properties. For example, this query would allow you to wire up a view which lists a customer’s contact name and company name:
//We only need the company name and contact name var query = breeze.EntityQuery.from('Customers') .select('CompanyName, ContactName');
You can also project properties from related entities. For example, this query retrieves a list of customers who placed orders with freight charges over $500:
var query = breeze.EntityQuery.from('Orders') .where('Freight', FilterQueryOp.GreaterThan, 500) .select('Customer.CompanyName');
If you know you need related entities up front, it’s often a good idea to grab all of the data in a single call. Maybe you need to build a view which displays a list of customers in Mexico and their related orders. This query eagerly loads the customer’s orders:
var query = breeze.EntityQuery.from('Customers') .where('Country', 'eq', 'Mexico') .expand('Orders');
How easy is that?!