I am very excited to announce developer preview #1 of the official Linq provider for Couchbase N1QL! This is a very early pre-release to introduce the provider, preview it’s basic functionality and illustrate how to use it. In this blog, I will create a sample application that goes over the steps on how to use the provider today.
Being a pre-release expect the public API to change significantly until the beta becomes available. Note that the Couchbase.Linq project depends upon the GA release of the SDK. Do not use this provider in production until the GA of 2.2.0 SDK!
Getting the package
The package is a pre-release up on NuGet and can be found here. If you are using Visual Studio, you’ll probably want to either use the NuGet Package Manager or the NuGet Package Manager Console to include the dependencies in your project.
First, create a console application using Visual Studio. Then using the Package Manager, search for Couchbase.Linq:
Make sure you select “Include Prerelease” when you search, otherwise the package will not turn up in the search results. Click “install” and all of the dependencies will be installed for you. Finally close the Package Manager dialog.
Configuration and Initialization
The current Couchbase Linq provider has a hard dependency on the ClusterHelper class from the Couchbase .NET 2.1 SDK. The ClusterHelper is class that makes it easy to manage buckets and other resources that for performance reasons must be long-lived. It’s a singleton for a Cluster object and a “multiton” for Bucket references. This dependency will likely be removed in future versions, but must be considered when you use the Linq provider in your application.
To handle this dependency, you simply have to use the ClusterHelper in your application and explicitly call Initialize() exactly once within your application’s lifespan. By default localhost will be used to bootstrap the client, but you can use the overload that takes a ClientConfiguration that can be customized as you please.
In the gist above, we create a new configuration and specify a Couchbase Server instance installed locally as the bootstrap target. Then we initialize the cluster helper object by calling Initialize and passing in the configuration.
Creating a DbContext instance
Once you have initialized the ClusterHelper, you’ll create a DbContext object which is abstraction over the underlying data store (the Couchbase Bucket) and provides a means of building queries and (soon) grouping together changes which will be submitted back to the bucket.
The DbContext constructor takes a Cluster object and then name of the Couchbase bucket to use in the query.
Note that once you create DbContext, it can be used over and over again and you can perform JOINs against itself as well. In a later post, i’ll show how to inherit from DbContext to make concrete query objects that map to the documents within your bucket; eventually we will provide tool support to generate these objects automagically from a bucket.
Building a Linq query
Creating a Linq query is no different from using any other Linq provider for the most part; the differences are that Linq2Couchbase supports N1QL keywords and concepts like NEST, UNNEST and USE KEYS, amongst others.
Like all Linq queries, the execution is deferred until you enumerate on it:
Here we are simply enumerating the query we created in the previous step. The provider will take the expression that has been generated and will convert it to a N1QL query and execute it returning only the rows portion of the response. Note that exceptions will be thrown by the Linq provider which is different behavior than the Couchbase SDK, which returns the exception as a property of the IQueryResult implementation.
What about that WHERE clause?
Did you notice that we are not specifying a WHERE clause to filter by document type? Since buckets are a keyspace of heterogeneous documents, without a predicate to filter the results the query generated would return every single Name attribute of every document within the bucket (note that beer-sample bucket has beer and brewery document types). Since we want to stay DRY and adding a WHERE type=”[document-type]” for every query would be tedious, there is a way to specify the document filter as an attribute to the POCO we are using for our projection.
Here in the POCO definition, we have added a EntityTypeFilter and specified “beer” as the document type we should be targeting with our query. Cool stuff!