3
\$\begingroup\$

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; }

}
\$\endgroup\$
3
\$\begingroup\$

In your Repository<T>, you might want to check the EntityState of your entity before manipulating them in your DbSet like this:

 public  void Add(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State != EntityState.Detached)
        {
            dbEntityEntry.State = EntityState.Added;
        }
        else
        {
            DbSet.Add(entity);
        }
    }

    public void Update(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State == EntityState.Detached)
        {
            DbSet.Attach(entity);
        }
        dbEntityEntry.State = EntityState.Modified;
    }

    public void Delete(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State != EntityState.Deleted)
        {
            dbEntityEntry.State = EntityState.Deleted;
        }
        else
        {
            DbSet.Attach(entity);
            DbSet.Remove(entity);
        }
    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.