The Problem
I’ve done a lot of work with SharePoint in my career. I’m talking big fat customization projects with 200,000+ lines of code. One thing that’s always irked me is the ugly code that tends to proliferate in these projects like the following:
using (SPSite mySite = new SPSite("http://SPSiteUrl"))
{
using (SPWeb myWeb = mySite.OpenWeb())
{
SPList list = myWeb.Lists["MyList"];
SPListItem item = list.GetItemById(2);
item["MyField"] = "A new value";
item.Update();
}
}
As long as this is well encapsulated it’s fine, but in practice there are several problems with code like this:
- It tends to bleed into every corner of your code base. It’s not uncommon to find stuff like this in the code behind for a web form (Blahhh). When code like this is not properly wrapped and encapsulated, it tightly couples the whole codebase to the SharePoint object model and reduces its portability and maintainability.
- SPListItems commonly wind up representing business entities in a system. These entities nearly always have custom data and behavior that is not included on the SPListItem type. This means that instead of interacting with strongly-typed domain objects, you have to deal with weakly typed SPListItems. In practice, this tends to push people towards a Transaction Script design instead of a rich Domain Model.
- The amount of code you’re required to write to do something simple, like update or get a list item is considerable and requires you to provide at least three strings.
- This type of coding is not conducive to unit testing at all. Since everything is tightly coupled to SharePoint it makes validating your business logic with unit tests a huge headache.
- What happens if the name of “MyField” changes? You’ll have to manually find every occurrence of that string and change it. That my friend, is a pain in the ass.
My main beef with this is you wind up with ugly code that violates several widely accepted design principles. I’ve thought a lot about what the right way to fix this is. The answer depends on the project. The rest of this article discusses an approach to abstracting data access called the Repository pattern that solves some of these problems.
A Solution
The Repository Pattern can help clean things up significantly. Here’s Martin Fowler’s definition:
“A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.”
Repositories provide a consistent and easily understood way to access data. They also abstract away the implementation of

the data access so you don’t wind up tightly coupling your business logic to any given data source.
For simplicity, lets break up the solutions into the following projects:
1. Project.Core: This contains all of the domain objects and interfaces for the repositories. There is no hard-wired dependency on the SPRepository project.
2. Project.SPRepository: This contains concrete implementations of the Repository interfaces defined in the Project.Core project. This assembly is loaded by the Core using an inversion of control container.
3. Presentation Code: Depending on the project this will differ, but the important thing is the only project the presentation code needs to reference is Project.Core.
You get a ton of benefits from setting up your projects this way.
- Your domain objects and logic are not dependent on any concrete implementation.
- Since your data access implementation is pluggable, unit tests for your domain code can be written without needing to set up and tear down any data in a SharePoint environment or database.
- SharePoint code is entirely encapsulated in the Project.SPRepository project since this is the only project with a reference to the Microsoft.SharePoint.dll.
- UI Code is dependent only on the Project.Core.
- There’s a consistent and easy to understand mechanism for accessing data throughout the system that will not change if you change platforms.
Repository Design
Let’s take a simple example. Consider a case where we have one custom content type called “Person” and a list instance
deployed to SharePoint called “PersonList”. Our simple content type has two custom fields: “FirstName” and “LastName”. Take a look at the core project structure on the right.
You can see that the core project has no concrete dependency on SharePoint. This project encapsulates the domain objects, the repository interfaces and the repository factory.
Lets start by defining the Domain objects. In this case it’s simple, there’s one entity called Person, but let’s stick to good design principles and create an abstract base so our design is extensible:
namespace Project.Core
{
/// <summary>
/// Represents a base class for all entities
/// </summary>
public abstract class EntityBase
{
/// <summary>
/// The primary key identifier for the entity
/// </summary>
public int ID { get; private set; }
/// <summary>
/// The person who created the entity
/// </summary>
public string CreatedBy { get; set; }
/// <summary>
/// The last person to modify the entity
/// </summary>
public string LastModBy { get; set; }
/// <summary>
/// The title of the entity
/// </summary>
public string Title { get; set; }
/// <summary>
/// Default Constructor. Initializes the entity with all the default values.
/// </summary>
protected EntityBase() : this(0, string.Empty, string.Empty, string.Empty)
{}
/// <summary>
/// Initializes the entity with the input values
/// </summary>
/// <param name="id">The id of the entity</param>
/// <param name="title">The title of the entity</param>
/// <param name="createdBy">The person who created the entity</param>
/// <param name="lastModBy">The last person to modify the entity</param>
protected EntityBase(int id, string title, string createdBy, string lastModBy)
{
ID = id;
Title = title;
CreatedBy = createdBy;
LastModBy = lastModBy;
}
/// <summary>
/// Creates or updates the entity
/// </summary>
public abstract void Save();
}
}
Then we would define the Person entity:
using Project.Core.Repository;
namespace Project.Core
{
/// <summary>
/// Represents a person entity
/// </summary>
public class Person : EntityBase
{
/// <summary>
/// The first name of the Person
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// The last name of the Person
/// </summary>
public string LastName { get; set; }
/// <summary>
/// Initializes an instance of Person with all of the default values
/// </summary>
public Person() : this(string.Empty, string.Empty)
{}
/// <summary>
/// Initializes an instance of Person with the input first name and last name
/// </summary>
/// <param name="firstName">The first name of the person</param>
/// <param name="lastName">The last name of the person</param>
public Person(string firstName, string lastName) : this(0, string.Empty, string.Empty, string.Empty, firstName, lastName)
{}
/// <summary>
/// Initializes an instance of Person with all of the input parameters
/// </summary>
/// <param name="id">The primary key ID of the user</param>
/// <param name="title">The title of the user</param>
/// <param name="createdBy">The user who created this person</param>
/// <param name="lastModBy">The user who last modified this person</param>
/// <param name="firstName">The first name of the person</param>
/// <param name="lastName">The last name of the person</param>
public Person(int id, string title, string createdBy, string lastModBy, string firstName, string lastName)
: base (id, title, createdBy, lastModBy)
{
FirstName = firstName;
LastName = lastName;
}
/// <summary>
/// Creates or updates the Person
/// </summary>
public override void Save()
{
IPersonRepository personRepo = RepositoryFactory.GetRepository<IPersonRepository>();
if (ID > 0)
{
personRepo.Update(this);
}
else
{
personRepo.Add(this);
}
}
}
}
The next step is defining the interfaces for accessing the repository. This breaks down into two parts. First, you have to define the interfaces for the repository itself. Second, you must define the framework that will be used to query the repository.
IRepository
using System.Collections.Generic;
using Project.Core.Repository.Queries;
namespace Project.Core.Repository
{
/// <summary>
/// Defines the basic contract used by all repositories
/// </summary>
/// <typeparam name="T">The type of domain object that the repository will be used to retrieve</typeparam>
/// <typeparam name="TE">The type of the query object that is used to search for objects in this repository</typeparam>
public interface IRepository<T, TE> where T : EntityBase where TE : QueryBase<T>
{
/// <summary>
/// Adds the input item to the repository
/// </summary>
/// <param name="newEntity"></param>
void Add(T newEntity);
/// <summary>
/// Deletes the input item from the repository
/// </summary>
/// <param name="id"></param>
void Delete(int id);
/// <summary>
/// Updates the input item in the repository
/// </summary>
/// <param name="entity"></param>
void Update(T entity);
/// <summary>
/// Gets the item with the input id from the repository
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
T Get(int id);
/// <summary>
/// Gets all of the items from the repository
/// </summary>
/// <returns></returns>
IList<T> All();
/// <summary>
/// Finds items matching the input query object in the repository
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
IList<T> Find(TE query);
}
}
Notice that IRepository takes two generic parameters. The first specifies the type of the entity that will be contained in the repository. The second defines the type of object that will be used to query the repository. This second type is one of the more powerful aspects of this pattern. What we’re doing here is defining a context-independent interface for accessing and querying data. Setting things up this way allows us to send queries to any data source without changing the Core project. Take a look at how the query objects are set up.
QueryBase
namespace Project.Core.Repository.Queries
{
/// <summary>
/// Base class for all query objects. Objects that inherit from this class are used to query repositories in the Core.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class QueryBase<T> where T : EntityBase
{
/// <summary>
/// The template object that is matched against when querying the repository.
/// </summary>
private T _template;
/// <summary>
/// The template object that is matched against when querying the repository.
/// </summary>
public T Template
{
get { return _template; }
set{ _template = value; }
}
/// <summary>
/// Initializes the query object
/// </summary>
protected QueryBase()
{
}
/// <summary>
/// Initializes the query object
/// </summary>
/// <param name="template">The template object used to match records in the repository</param>
protected QueryBase(T template)
{
_template = template;
}
}
}
Objects implementing QueryBase could contain additional parameters for the query.
The last step is defining an interface that the repository implementations will use to map objects from their data sources into domain objects. Here’s the code for defining the mapper:
IMapper
namespace Project.Core.Repository
{
/// <summary>
/// Defines a common interface for mapping domain entities into data records and vice versa.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IMapper<T> where T : EntityBase
{
/// <summary>
/// Maps a data record into a domain object
/// </summary>
/// <param name="dataSource">The data source object</param>
/// <returns>The mapped domain entity</returns>
T FromData(object dataSource);
/// <summary>
/// Maps a domain entity into a data record
/// </summary>
/// <param name="domainEntity"></param>
/// <returns></returns>
object ToData(T domainEntity);
}
}
That covers all the pieces that you need in the Core. Whew! If you’re still with me pat yourself on the back. We’re almost done.
SPRepository
The next step is implementing the repository for SharePoint. We need to set up a simple project that provides concrete
implementations for all of our repositories (see right).
NOTE: In this implementation I’m leveraging LINQ to SharePoint. It’s an extremely flexible mechanism for querying SharePoint 2010 data. There is a performance hit that comes with this flexibility, but for our purposes here it’s acceptable.
Person Mapper
Here’s the person mapper:
using System;
using Project.Core;
using Project.Core.Repository;
namespace Project.SPLinqRepository.Mappers
{
/// <summary>
/// Provides mapping functionality between the Person SharePoint content type and the Person domain object
/// </summary>
internal class PersonMapper : IMapper<Person>
{
/// <summary>
/// Maps an Person into a Person
/// </summary>
/// <param name="dataSource">The data source entity</param>
/// <returns>The fully populated domain object</returns>
public Person FromData(object dataSource)
{
LinqPerson aewPerson = dataSource as LinqPerson;
if(aewPerson == null)
{
return null;
}
Person person = new Person(
aewPerson.Id.Value,
aewPerson.Title,
aewPerson.CreatedBy,
aewPerson.ModifiedBy,
aewPerson.FirstName,
aewPerson.LastName);
return person;
}
/// <summary>
/// Maps a Person into an AEWPerson
/// </summary>
/// <param name="domainEntity">The Person to transform into an AEWPerson</param>
/// <returns>The fully populated AEWPerson</returns>
public object ToData(Person domainEntity)
{
if (domainEntity == null)
{
return null;
}
LinqPerson person = new LinqPerson();
if (domainEntity.ID > 0)
{
person.Id = domainEntity.ID;
}
person.CreatedBy = domainEntity.CreatedBy;
person.ModifiedBy = domainEntity.LastModBy;
person.Title = domainEntity.Title;
person.FirstName = domainEntity.FirstName;
person.LastName = domainEntity.LastName;
return person;
}
}
}
PersonRepository
Here’s the implementation of the person repository:
public class PersonRepository : IRepository<Person, PersonQuery>
{
public void Add(Person newEntity)
{
using (DataContext context = new DataContext(Configuration.SiteUrl))
{
PersonMapper personMapper = new PersonMapper();
LinqPerson aewPerson = personMapper.ToData(newEntity) as LinqPerson;
context.PersonList.InsertOnSubmit(aewPerson);
context.SubmitChanges();
}
}
public void Delete(int id)
{
using (DataContext context = new DataContext(Configuration.SiteUrl))
{
LinqPerson aewPerson = context.PersonList.SingleOrDefault(p => p.Id == id);
if (aewPerson != null)
{
context.PersonList.DeleteOnSubmit(aewPerson);
context.SubmitChanges();
}
}
}
public void Update(Person entity)
{
using (DataContext context = new DataContext(Configuration.SiteUrl))
{
PersonMapper personMapper = new PersonMapper();
LinqPerson aewPerson = personMapper.ToData(entity) as LinqPerson;
context.PersonList.Attach(aewPerson);
context.SubmitChanges();
}
}
public Person Get(int id)
{
Person person = null;
using (AEWDataContext context = new AEWDataContext(AEWConfiguration.SiteUrl))
{
LinqPerson aewPerson = context.PersonList.SingleOrDefault(p => p.Id == id);
PersonMapper personMapper = new PersonMapper();
person = personMapper.FromData(aewPerson);
}
return person;
}
public IList<Person> All()
{
IList<Person> people = new List<Person>();
using (DataContext context = new DataContext(Configuration.SiteUrl))
{
PersonMapper mapper = new PersonMapper();
foreach (LinqPerson aewPerson in context.PersonList)
{
Person person = mapper.FromData(aewPerson);
people.Add(person);
}
}
return people;
}
public IList<Person> Find(PersonQuery query)
{
IList<Person> people = new List<Person>();
Expression<Func<LinqPerson, bool>> predicate = PredicateBuilder.True<LinqPerson>();
using (DataContext context = new DataContext(Configuration.SiteUrl))
{
if (!string.IsNullOrEmpty(query.Template.FirstName))
{
predicate = predicate.And<AEWPerson>(p => p.FirstName == query.Template.FirstName);
}
if (!string.IsNullOrEmpty(query.Template.LastName))
{
predicate = predicate.And<AEWPerson>(p => p.LastName == query.Template.LastName);
}
if (!string.IsNullOrEmpty(query.Template.CreatedBy))
{
predicate = predicate.And<AEWPerson>(p => p.CreatedBy == query.Template.CreatedBy);
}
if (!string.IsNullOrEmpty(query.Template.LastModBy))
{
predicate = predicate.And<AEWPerson>(p => p.ModifiedBy == query.Template.LastModBy);
}
var aewPeople = context.PersonList.Where(predicate);
PersonMapper personMapper = new PersonMapper();
foreach (LinqPerson aewPerson in aewPeople)
{
Person person = personMapper.FromData(aewPerson);
people.Add(person);
}
}
return people;
}
}
Repository in Action
So now that you’ve set up this Repository, what does it look like when you actually use it? Here are a few examples of core use cases.
Adding an Item
//Get the repository
IPersonRepository personRepo = RepositoryFactory.GetRepository<IPersonRepository>();
//Create a new person object
Person hanz = new Person("Hanz", "Vagner");
//Add the person to the repository
personRepo.Add(hanz);
Getting an Item
//Get the repository
IPersonRepository personRepo = RepositoryFactory.GetRepository<IPersonRepository>();
//Get the person from the repository
Person person = personRepo.Get(3);
Saving an Item
//Get the repository
IPersonRepository personRepo = RepositoryFactory.GetRepository<IPersonRepository>();
//Get the person from the repository
Person person = personRepo.Get(3);
//Change the first name
person.FirstName = "Franz";
//Save your change
person.Save();
Finding an Item
//Get the repository
IPersonRepository personRepo = RepositoryFactory.GetRepository<IPersonRepository>();
//Create a query
PersonQuery personQuery = new PersonQuery(new Person { FirstName="Hanz" });
//Find all people with the first name "Hanz"
IList<Person> people = personRepo.Find(personQuery);
Conclusion
As you can see, the repository gives you a consistent interface for accessing and manipulating domain objects regardless of the data source implementation. I hope you found this helpful. In my experience this sort of decoupling can be very helpful. It’s not right for every scenario, but if you find yourself in a situation where code re-usability is paramount, this approach has a lot of benefits.