Skip to content

Instantly share code, notes, and snippets.

@hanssens
Last active December 2, 2015 14:51
Show Gist options
  • Save hanssens/63db5bce5674cc950f3e to your computer and use it in GitHub Desktop.
Save hanssens/63db5bce5674cc950f3e to your computer and use it in GitHub Desktop.
GenericDataRepository for easy CRUD operations with RavenDB
namespace Hanssens.Integrations.RavenDb
{
/**
* Built by : hanssens.com
* License : MIT
* See also : https://gist.github.com/hanssens/63db5bce5674cc950f3e
*/
/// <summary>
/// Contract required for all objects that want to use the GenericDocumentRepository.
/// </summary>
/// <remarks>
/// Extend or modify it as you desire. The only requirement is that 'Id' exists, but
/// you may change its type to for example long, string or Guid.
/// </remarks>
public interface IRavenDbEntity {
int Id { get; set; }
}
/// <summary>
/// Provides a generic CRUD repository for any object type that derives from IRavenDbEntity.
/// </summary>
/// <typeparam name="T">The class type, which should implement IRavenDbEntity.</typeparam>
/// <remarks>
/// Each individual function in this class is responsible, and self-manages the
/// opening and closing of session(s). Therefor every instance of the GenericDocumentRepository
/// should be as short-lived as possible.
/// The reason for this is a trade-off: either the user, e.g. calling application, is responsible
/// for managing sessions - or this repository is. Not having to bother the calling application
/// with this seems to be the neater approach.
/// Another noteworthy element is that several operations require "knowledge" of the unique identifier.
/// Therefor the IRavenDbEntity interface is defined. You can adjust this to your will by changing its
/// type, for example to long or Guid, if you wish.
/// </remarks>
public class GenericDocumentRepository<T> : IDisposable where T : IRavenDbEntity
{
protected string House { get; set; }
/// <summary>
/// Provides access to an already instantiated data access provider, e.g. the DocumentStore.
/// </summary>
/// <remarks>
/// Note that this property deliberately has a protected access-level; you do not want your
/// consumers to sneakily directly address the DocumentStore.
/// </remarks>
protected Raven.Client.Document.DocumentStore DataContext { get; set; }
/// <summary>
/// Initialises a new instance of the GenericDocumentRepository.
/// </summary>
public GenericDocumentRepository() : this(new DocumentStore()) { }
/// <summary>
/// Initialises a new instance of the GenericDocumentRepository.
/// </summary>
public GenericDocumentRepository(DocumentStore documentStore)
{
DataContext = documentStore;
}
/// <summary>
/// Deletes a single document from the database.
/// </summary>
/// <param name="id">Unique identifier of the object to be deleted.</param>
public void Delete(long id)
{
using (var session = DataContext.OpenSession())
{
var instance = session.Load<T>(id);
session.Delete(instance);
session.SaveChanges();
}
}
/// <summary>
/// Inserts a single item into the database.
/// </summary>
/// <param name="instance">The instance to be inserted.</param>
/// <remarks>
/// Use 'BatchInsert' for multiple items.
/// </remarks>
public T Insert(T instance)
{
var now = DateTime.Now;
instance.CreatedOn = now;
instance.LastModifiedOn = now;
using (var session = DataContext.OpenSession())
{
session.Store(instance);
session.SaveChanges();
return instance;
}
}
/// <summary>
/// Loads a single instance from the database.
/// </summary>
/// <param name="id">Unique identifier of the object.</param>
public T Get(long id)
{
var returnValue = default(T);
using (var session = DataContext.OpenSession())
{
returnValue = session.Load<T>(id);
}
return returnValue;
}
/// <summary>
/// Fetches a list of items, optionally limited by the 'skip' and 'take' filters.
/// </summary>
/// <param name="skip">Amount of records to skip. Defaults to '0'.</param>
/// <param name="take">Amount of records to fetch. Defaults to '50'.</param>
/// <returns>Returns a collection of items.</returns>
public virtual IEnumerable<T> GetAll(int skip = 0, int take = 50)
{
using (var session = DataContext.OpenSession())
{
return session.Query<T>()
.Skip(skip)
.Take(take);
}
}
/// <summary>
/// Fetches a specific list of items, by a collection of id's.
/// </summary>
/// <param name="identifiers">List of unique identifiers</param>
/// <returns>Returns a collection of items.</returns>
public virtual IEnumerable<T> GetAll(IEnumerable<int> identifiers)
{
var returnValue = new List<T>();
using (var session = DataContext.OpenSession())
{
foreach (var id in identifiers)
{
returnValue = session.Query<T>()
.Where(t => identifiers.Contains(t.Id))
.ToList();
}
}
return returnValue.ToList();
}
public virtual IQueryable<T> Query(Expression<Func<T, bool>> predicate)
{
using (var session = DataContext.OpenSession())
{
return session.Query<T>().Where(predicate);
}
}
public T Update(T instance)
{
throw new NotImplementedException("This is something you may do yourself");
}
public void Dispose()
{
DataContext.Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment