RavenDB - Image Gallery Application (VI) - Entities, Repositories and Commands

Published on 2010-10-3

The code for this and all other entries can be found here: http://github.com/robashton/RavenGallery/ 

In order to add our first piece of functionality (registration), we’ll need the ability to store and retrieve User Entities, and that means creating an underlying document as well as the entity itself, along with a repository for dealing with the users and the IDocumentSession.

The Document

For now there is very little we need on the User document, we need to be able to identify the user and we need to be able to authenticate them, the following simple document model will be used for now therefore.

   1:      public class UserDocument
   2:      {
   3:          public string Id { get; set; }
   4:          public string Username { get; set; }
   5:          public string PasswordHash { get; set; }
   6:      }

The Entity

   1:      public class User : IEntity<UserDocument>
   2:      {
   3:          private UserDocument innerUser;        
   4:   
   5:          public User(UserDocument innerUser)
   6:          {
   7:              this.innerUser = innerUser;
   8:          }
   9:   
  10:          UserDocument IEntity<UserDocument>.GetInnerDocument()
  11:          {
  12:              return innerUser;
  13:          }
  14:      }

Further constructors can be added as needed (if the process of construction is simple then a command could invoke the constructor manually, and if it is complicated, it could resort to a factory), but the above pattern is how I’m going to be creating the rest of my entities and documents.

The Repository

The base functionality for the repository can actually be carried out via a handy base class that implements the interface for us, and that is what I have done:

   1:      public abstract class EntityRepository<TEntity, TDoc> : IEntityRepository<TEntity, TDoc> where TEntity : IEntity<TDoc>
   2:      {
   3:          private IDocumentSession documentSession;
   4:   
   5:          public EntityRepository(IDocumentSession documentSession)
   6:          {
   7:              this.documentSession = documentSession;
   8:          }
   9:   
  10:          public TEntity Load(string id)
  11:          {
  12:              return Create(this.documentSession.Load<TDoc>(id));
  13:          }
  14:   
  15:          public void Add(TEntity entity)
  16:          {
  17:              this.documentSession.Store(entity.GetInnerDocument());
  18:          }
  19:   
  20:          public void Remove(TEntity entity)
  21:          {
  22:              this.documentSession.Delete(entity.GetInnerDocument());
  23:          }
  24:   
  25:          protected abstract TEntity Create(TDoc doc);
  26:      }

The only piece of functionality we can’t easily keep common is the process of creating the entity from the document, so we leave that responsibility to the individual repositories for now.

The user repository therefore looks like this:

   1:      public interface IUserRepository : IEntityRepository<User, UserDocument>
   2:      {
   3:   
   4:      }

with
   1:      public class UserRepository : EntityRepository<User, UserDocument>
   2:      {
   3:          public UserRepository(IDocumentSession documentSession) : base(documentSession) { }
   4:   
   5:          protected override User Create(UserDocument doc)
   6:          {
   7:              return new User(doc);
   8:          }
   9:      }
Other methods could be added to IUserRepository to do user-specific request operations, and any consumer of the user repository need only ask for an IUserRepository via their constructor in order for StructureMap to provide it via its default conventions.

The Command Invoker

The implementation of this is very simple, here it is without any error handling

   1:      public class CommandInvoker : ICommandInvoker
   2:      {
   3:          private IContainer container;
   4:          private IDocumentSession documentSession;
   5:   
   6:          public CommandInvoker(IContainer container, IDocumentSession documentSession)
   7:          {
   8:              this.container = container;
   9:              this.documentSession = documentSession;
  10:          }
  11:   
  12:          public void Execute<T>(T command)
  13:          {
  14:              var handler = container.GetInstance<ICommandHandler<T>>();
  15:              handler.Handle(command);
  16:              documentSession.SaveChanges();
  17:          }
  18:      }

As we can see, if the application sends a command, an appropriate handler will be located and assuming nothing goes wrong, SaveChanges will be invoked and the transaction will be flushed. If something does go wrong, the transaction will go ignored. This should be adequate for now.

The code covered here should give us the ability to save/retrieve/modify entities – and also the ability to send neatly packaged commands from the controller after validation has taken place, in the next entry we’ll use the above framework to add functionality to register a new user.

2020 © Rob Ashton. ALL Rights Reserved.