I've done a LOT of reading about creating a Unit Of Work and Repository based implementation for my Entity Framework based application. I have come up with the following - what problems can you find?
The theory of making the actual SQL Server unit of work, context, and repository coupled to entity framework is that these three implementations will not be used independently. I can create a fake unit Unit of work and Repository for unit testing without worrying about the context as the Unit of Work is responsible for instantiating the concrete repository.
p.s. Do I need to implement IDisposable on the repository?
Dgc.CriminalJustice.Model
Repository Interface
public interface IRepository<T> : IDisposable
where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(int id);
IEnumerable<T> All();
IEnumerable<T> Find(Expression<Func<T, bool>> filter = null, string includeProperties = "");
}
Unit of work interface
public interface IUnitOfWork : IDisposable
{
IRepository<Person> PersonRepository { get; }
void Save();
}
Dgc.CriminalJustice.Data.SqlServer
Entity Framework Context
public class CriminalJusticeContext : DbContext
{
static CriminalJusticeContext()
{
Database.SetInitializer<CriminalJusticeContext>(null);
}
public CriminalJusticeContext()
: base("Name=CriminalJusticeContext")
{
}
public DbSet<Address> Addresses { get; set; }
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new Mapping.AddressMap());
modelBuilder.Configurations.Add(new Mapping.PersonMap());
modelBuilder.Configurations.Add(new Mapping.AliasMap());
modelBuilder.Configurations.Add(new Mapping.CaseNoteMap());
}
}
Entity framework based Repository
public class Repository<T> : IRepository<T>
where T : class
{
private CriminalJusticeContext context;
private IDbSet<T> dbSet;
internal Repository(CriminalJusticeContext criminalJusticeContext)
{
this.context = criminalJusticeContext;
this.dbSet = criminalJusticeContext.Set<T>();
}
public void Add(T entity)
{
dbSet.Add(entity);
}
public void Delete(T entity)
{
dbSet.Remove(entity);
}
public void Update(T entity)
{
dbSet.Attach(entity);
context.Entry(entity).State = EntityState.Modified;
}
public T GetById(int id)
{
return dbSet.Find(id);
}
public IEnumerable<T> All()
{
return dbSet.ToList();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> filter = null, string includeProperties = "")
{
IQueryable<T> query = dbSet;
if (filter != null)
{
query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
return query.ToList();
}
public void Dispose()
{
throw new NotImplementedException();
}
}
Entity Framework based Unit Of Work
public class UnitOfWork : IUnitOfWork
{
private CriminalJusticeContext context = new CriminalJusticeContext();
private Repository<Model.Person> personRepository;
public IRepository<Model.Person> PersonRepository
{
get
{
if (personRepository == null)
{
personRepository = new Repository<Model.Person>();
}
return personRepository;
}
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Dgc.CriminalJustice.Model
public class Person
{
public Person()
{
this.Aliases = new List<Alias>();
this.CaseNotes = new List<CaseNote>();
}
public int PersonRef { get; private set; }
public string Title { get; private set; }
public string FirstName { get; private set; }
public string PreferredForename { get; private set; }
public string Surname { get; private set; }
public string NameSuffix { get; private set; }
public string Gender { get; private set; }
public Nullable<System.DateTime> DateBirth { get; private set; }
public bool EstimatedDateOfBirth { get; private set; }
public string AddressRef { get; private set; }
public Nullable<System.DateTime> DateofDeath { get; private set; }
public string URN { get; private set; }
public string SwissRef { get; private set; }
public string CJSwissRef { get; private set; }
public Address ContactAddress { get; set; }
public ICollection<Alias> Aliases { get; set; }
public ICollection<CaseNote> CaseNotes { get; set; }
}
public class Address
{
public string AddressRef { get; private set; }
public string Address1 { get; private set; }
public string Address2 { get; private set; }
public string Address3 { get; private set; }
public string Address4 { get; private set; }
public string Postcode { get; private set; }
}
public class Alias
{
public int PersonRef { get; private set; }
public string Forename { get; private set; }
public string Surname { get; private set; }
}
public class CaseNote
{
public int CaseNoteRef { get; private set; }
public int PersonRef { get; private set; }
public System.DateTime ContactDate { get; private set; }
public int WhoWithId { get; private set; }
public int ContactTypeId { get; private set; }
public int VenueId { get; private set; }
public int AuthorId { get; private set; }
public int PurposeId { get; private set; }
public string NoteText { get; private set; }
}