Sunday, 12 July 2015

Using the Model-Store pattern in Inversion (part 4)

This post is the fourth in a series about using a Model-Store pattern in the Inversion behavioural micro-framework for .Net (see: https://github.com/guy-murphy/inversion-dev).

The code that I have been developing as part of this article series can be found at https://github.com/fractos/inversion-data

The first part can be found here.
The second part can be found here.
The third part can be found here.

Using the Store


In this instalment, I'm going to show you what using the pattern looks like. I'll put together a few example functions that use the IUserStore interface to access and manipulate data stored in an underlying MongoDB instance.


Configuring and Instantiation



We are going to use the MongoDBUserStore class that I showed you in the previous article to perform operations in MongoDB. To instantiate it, we will need a few details that describe the MongoDB connection-string, the database name and the name of the collection used for users.

I am using a local MongoDB server, which has a database called 'test' and I want to access model objects in a collection called 'users':

const string ConnectionString = "mongodb://localhost";
const string DatabaseName = "test";
const string CollectionName = "users";
view raw gistfile1.cs hosted with ❤ by GitHub


Those details can then be passed to the MongoDBUserStore constructor:

MongoDBUserStore userStore = new MongoDBUserStore(ConnectionString, DatabaseName, CollectionName);
view raw gistfile1.cs hosted with ❤ by GitHub


But since this is an IDisposable and we only actually care about the interface methods, then more correctly we should be calling it like this:

using(IUserStore userStore = new MongoDBUserStore(ConnectionString, DatabaseName, CollectionName)) {
userStore.Start();
// do something with the store here
}
view raw gistfile1.cs hosted with ❤ by GitHub


At which point we are off to the races.

However, the Store could be gained by dependency injection behind an interface, or fetched from a service container (such as Inversion.Naiad, which implements Inversion.Process.IServiceContainer). I'll try and cover the use of IServiceContainer in a separate article, but the call might look something like this:

using(IUserStore userStore = serviceContainer.GetService<IUserStore>("store-user")) {
userStore.Start();
// do something with the store here
}
view raw gistfile1.cs hosted with ❤ by GitHub


By using interfaces alone, you can keep your code free from references to the assemblies needed for accessing MongoDB, keeping the main application as agnostic as possible. All the code cares about is the IUserStore interface.

Asking a service container for an object of type IUserStore which has the label "store-user" will cause the container to perform any configuration required according to the instructions that are associated with the service label. The application doesn't have to care about the configuration of the Store because it is handled by the container. This is a form of loose coupling by service location.

The more agnostic your code is about its dependencies, the more flexible your application can be.

Creating a collection of Users in MongoDB


This method assumes that you have a list of User models which are ready to be written to the database. I've included the basic version of instantiating the Store just to keep it simple.

static void SaveUsers(IList users)
{
using (IUserStore userStore = new MongoDBUserStore(ConnectionString, DatabaseName, CollectionName))
{
userStore.Start();
foreach (User user in users)
{
userStore.Put(user);
}
}
}
view raw gistfile1.cs hosted with ❤ by GitHub


After this call, you should find that the User models have been written into MongoDB, complete with Object IDs.

Read a list of Users from MongoDB


This method will return all the users from MongoDB as a list of User models.

Note that the IEnumerable is converted to an IList with ToList() before the using statement has been terminated (and therefore the Store and its resources disposed) in order to avoid the enumeration code reading a closed connection.

static List<User> ReadUsers()
{
using (IUserStore userStore = new MongoDBUserStore(ConnectionString, DatabaseName, CollectionName))
{
userStore.Start();
return userStore.GetAll().ToList();
}
}
view raw gistfile1.cs hosted with ❤ by GitHub


Updating a list of Users


This function iterates through a passed list of User models, modifying their Password property and then writing them back into MongoDB. It makes use of the Mutate method on the User object in order to change an immutable object. The ID of the User model will remain unchanged, however, so the act of writing the data into MongoDB will perform an update rather than an insert.


static void UpdateUsers(IList<User> users)
using (IUserStore userStore = new MongoDBUserStore(ConnectionString, DatabaseName, CollectionName))
{
userStore.Start();
foreach (User user in users)
{
User updatedUser = user.Mutate(b =>
{
b.Password = // pick a random string from somewhere here
return b;
});
userStore.Put(updatedUser);
}
}
}
view raw gistfile1.cs hosted with ❤ by GitHub


Deleting a list of Users


This function will delete each of a list of User models from MongoDB.

static void DeleteUsers(IList<User> users)
{
using (IUserStore userStore = new MongoDBUserStore(ConnectionString, DatabaseName, CollectionName))
{
userStore.Start();
foreach (User user in users)
{
userStore.Delete(user);
}
}
}
view raw gistfile1.cs hosted with ❤ by GitHub


Next time ...


In the next (and final, so far ...) instalment, I'll wrap up with a conclusion and some thoughts about how this process went.

No comments:

Post a Comment