In addition to my previous post Windows Azure Table Storage in the development environment I’ve created a demo application in which responsibilities are distributed over classes in a way that hides the implementation details of Azure’s table storage.
The application is pretty simple, a one page ASP.NET app in which you can add/edit movies. The movies are displayed on the same page in a GridView.
The model has changed a bit. The RowKey is now filled with a GUID (instead of the title) to uniquely identify a movie in the table. The title now has a dedicated property. The PartitionKey remains the movie category as this helps Azure to partition the data over multiple servers if the load gets too heavy.
The StorageContext is the actual entry point to the data. It inherits from TableServiceContext and provides a property Movies that returns an IQueryable of type Movie, which can be used to query the data from storage. It also provides an AddMovie method to avoid exposure of the table name that is required for using TableServiceContext.AddObject.
To create a new StorageContext the StorageContextFactory can be used, which hides the creation/initialization of the StorageContext.
The repository is used to access the data from the application. Creation of a MovieRepository requires a context that implements IStorageContext (e.g. StorageContext), which can be obtained by the StorageContextFactory. The reason for using an interface to the context is to be able to replace the context by some other implementation, for example in case of a non-Azure application or in case of unit-testing.
MovieRepository repository = new MovieRepository(StorageContextFactory.GetContext()); // Get all movies IEnumerable<Movie> allMovies = repository.GetAll(); // Get a single movie Movie movie = repository.GetById(key); // Add a new movie Movie newMovie = MovieFactory.Create(); newMovie.PartitionKey = "Action"; newMovie.Title = "An action movie!"; repository.Add(newMovie);
A few notes:
- A MovieFactory is used to create a new Movie. In this factory an instance of a Movie is created and the RowKey property is populated with a new GUID. There are several alternatives but in this way you avoid unnecessary creation of GUIDs when objects are created by the context (in case you initialize in the Movie’s constructor), and you avoid the need for an initialization method that can potentially be forgotten to invoke.
- The Add and Update methods on repository directly save to the storage. This might not be what you want in other apps, but for this example (with only one update in each postback) it is good enough.