2
\$\begingroup\$

I am quite new to ASP.net and am currently trying to implement my data access layers of my application. I have so far implemented a generic repository pattern as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Entity;
using PayPlate.Models;
using System.Linq.Expressions;

namespace PayPlate.DAL
{
    public class GenericRepository<TEntity> where TEntity : class
    {
        internal PayPlateContext context;
        internal DbSet<TEntity> dbSet;

        public GenericRepository(PayPlateContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual TEntity GetByID(object id)
        {
            return dbSet.Find(id);
        }

        public virtual void Insert(TEntity entity)
        {
            dbSet.Add(entity);
        }

        public virtual void Delete(object id)
        {
            TEntity entityToDelete = dbSet.Find(id);
            Delete(entityToDelete);
        }

        public virtual void Delete(TEntity entityToDelete)
        {

            if (context.Entry(entityToDelete).State == EntityState.Detached)
            {
                dbSet.Attach(entityToDelete);
            }
            dbSet.Remove(entityToDelete);
        }

        public virtual void Update(TEntity entityToUpdate)
        {
            dbSet.Attach(entityToUpdate);
            context.Entry(entityToUpdate).State = EntityState.Modified;
        }
    }
}

I have also implemented a UnitOfWork pattern to perform actions against the database as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using PayPlate.Models;

namespace PayPlate.DAL
{
    public class UnitOfWork : IDisposable 
    { 
        private PayPlateContext context = new PayPlateContext();
        private GenericRepository<User> userRepository;
        private GenericRepository<Permission> permissionRepository; 
        private GenericRepository<Payroll> payrollRepository; 
        private GenericRepository<Function> functionRepository;
        private GenericRepository<PayrollIndexData> payrollIndexDataRepository;
        private GenericRepository<PayrollSelection> payrollSelectionRepository;
        private GenericRepository<GLRule> gLRuleRepository;
        private GenericRepository<Contract> contractRepository;
        private GenericRepository<CostGrp> costGrpRepository;
        private GenericRepository<AnalysisGrp> analysisGrpRepository;
        private GenericRepository<Job> jobRepository;
        private GenericRepository<Division> divisionRepository;
        private GenericRepository<AuthChain> authChainRepository;
        private GenericRepository<JobCode> jobCodeRepository;
        private GenericRepository<Pension> pensionRepository;


        public GenericRepository<GLRule> GLRuleRepository
        {
            get
            {

                if (this.gLRuleRepository == null)
                {
                    this.gLRuleRepository = new GenericRepository<GLRule>(context);
                }
                return gLRuleRepository;
            }
        }

        public GenericRepository<Contract> ContractRepository
        {
            get
            {

                if (this.contractRepository == null)
                {
                    this.contractRepository = new GenericRepository<Contract>(context);
                }
                return contractRepository;
            }
        }

        public GenericRepository<CostGrp> CostGrpRepository
        {
            get
            {

                if (this.costGrpRepository == null)
                {
                    this.costGrpRepository = new GenericRepository<CostGrp>(context);
                }
                return costGrpRepository;
            }
        }

        public GenericRepository<AnalysisGrp> AnalysisGrpRepository
        {
            get
            {

                if (this.analysisGrpRepository == null)
                {
                    this.analysisGrpRepository = new GenericRepository<AnalysisGrp>(context);
                }
                return analysisGrpRepository;
            }
        }

        public GenericRepository<Job> JobRepository
        {
            get
            {

                if (this.jobRepository == null)
                {
                    this.jobRepository = new GenericRepository<Job>(context);
                }
                return jobRepository;
            }
        }

        public GenericRepository<Division> DivisionRepository
        {
            get
            {

                if (this.divisionRepository == null)
                {
                    this.divisionRepository = new GenericRepository<Division>(context);
                }
                return divisionRepository;
            }
        }

        public GenericRepository<AuthChain> AuthChainRepository
        {
            get
            {

                if (this.authChainRepository == null)
                {
                    this.authChainRepository = new GenericRepository<AuthChain>(context);
                }
                return authChainRepository;
            }
        }

        public GenericRepository<JobCode> JobCodeRepository
        {
            get
            {

                if (this.jobCodeRepository == null)
                {
                    this.jobCodeRepository = new GenericRepository<JobCode>(context);
                }
                return jobCodeRepository;
            }
        }

        public GenericRepository<Pension> PensionRepository
        {
            get
            {

                if (this.pensionRepository == null)
                {
                    this.pensionRepository = new GenericRepository<Pension>(context);
                }
                return pensionRepository;
            }
        }

        public GenericRepository<PayrollSelection> PayrollSelectionRepository
        {
            get
            {

                if (this.payrollSelectionRepository == null)
                {
                    this.payrollSelectionRepository = new GenericRepository<PayrollSelection>(context);
                }
                return payrollSelectionRepository;
            }
        }

        public GenericRepository<Permission> PermissionRepository
        {
            get
            {

                if (this.permissionRepository == null)
                {
                    this.permissionRepository = new GenericRepository<Permission>(context);
                }
                return permissionRepository;
            }
        }

        public GenericRepository<User> UserRepository
        {
            get
            {

                if (this.userRepository == null)
                {
                    this.userRepository = new GenericRepository<User>(context);
                }
                return userRepository;
            }
        } 

        public GenericRepository<Payroll> PayrollRepository 
        { 
            get 
            { 

                if (this.payrollRepository == null) 
                { 
                    this.payrollRepository = new GenericRepository<Payroll>(context); 
                } 
                return payrollRepository; 
            } 
        } 

        public GenericRepository<Function> FunctionRepository 
        { 
            get 
            { 

                if (this.functionRepository == null) 
                {
                    this.functionRepository = new GenericRepository<Function>(context); 
                }
                return functionRepository; 
            } 
        }

        public GenericRepository<PayrollIndexData> PayrollIndexDataRepository
        {
            get
            {

                if (this.payrollIndexDataRepository == null)
                {
                    this.payrollIndexDataRepository = new GenericRepository<PayrollIndexData>(context);
                }
                return payrollIndexDataRepository;
            }
        }

        public void Save() 
        { 
            context.SaveChanges(); 
        } 

        private bool disposed = false; 

        protected virtual void Dispose(bool disposing) 
        { 
            if (!this.disposed) 
            { 
                if (disposing) 
                { 
                    context.Dispose(); 
                } 
            } 
            this.disposed = true; 
        } 

        public void Dispose() 
        { 
            Dispose(true); 
            GC.SuppressFinalize(this); 
        } 
    } 
}

This is my database context:

using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PayPlate.Models;

namespace PayPlate.DAL
{
    public class PayPlateContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Permission> Permissions { get; set; }
        public DbSet<Payroll> Payrolls { get; set; }
        public DbSet<Function> Functions { get; set; }
        public DbSet<JobCode> JobCodes { get; set; }
        public DbSet<Division> Divisions { get; set; }
        public DbSet<AuthChain> AuthChains { get; set; }
        public DbSet<Job> Jobs { get; set; }
        public DbSet<Pension> Pensions { get; set; }
        public DbSet<AnalysisGrp> AnalysisGrps { get; set; }
        public DbSet<CostGrp> CostGrps { get; set; }
        public DbSet<Contract> Contracts { get; set; }
        public DbSet<GLRule> GLRules { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }
}

And these are my models:

using System;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace PayPlate.Models
{
    public class PayrollSelection
    {
        public IEnumerable<Payroll> Payrolls { get; set; }
        public IEnumerable<User> Users { get; set; }
        public IEnumerable<Permission> Permissions { get; set; } 
    }

    public class PayrollIndexData
    {
        public IEnumerable<Payroll> Payrolls { get; set; }
        public IEnumerable<User> Users { get; set; }
        public IEnumerable<Function> Functions { get; set; }
        public IEnumerable<Permission> Permissions { get; set; } 
    }

    public class Payroll
    {
        public int PayrollID { get; set; }
        [Required(ErrorMessage = "Payroll title is required.")]
        [Display(Name = "Payroll")]
        [MaxLength(20)] 
        public string Title { get; set; }
        [Required(ErrorMessage = "C21 description is required.")]
        [Display(Name = "C21 Name")]
        [MaxLength(20)] 
        public string C21Name { get; set; }
        [Required(ErrorMessage = "Server name is required.")]
        [Display(Name = "Server Name")]
        [MaxLength(20)] 
        public string Server { get; set; }
        [Required(ErrorMessage = "Port is required.")]
        [Display(Name = "Port")]
        [MaxLength(5)] 
        public string Port { get; set; }
        [Required(ErrorMessage = "Connection string is required.")]
        [Display(Name = "Connection String")]
        [MaxLength(200)] 
        public string Connection { get; set; }
        public virtual ICollection<Permission> Permissions { get; set; }
    }

    public class SelectedPayroll
    {
        public string UserName { get; set; }
        public int UserID { get; set; }
        public int PayrollID { get; set; }
        public string Title { get; set; }
    }

    public class PermissionsPayrollGrp
    {
        public string Payroll { get; set; }
        public int UserCount { get; set; }
    } 

    public class Function
    {
        public int FunctionID { get; set; }
        [Required(ErrorMessage = "Function description is required.")]
        [Display(Name = "Function")]
        [MaxLength(20)] 
        public string Title { get; set; }
        public virtual ICollection<Permission> Permissions { get; set; }
    }

    public class Permission
    {
        public int PermissionID { get; set; }
        public int PayrollID { get; set; }
        public int FunctionID { get; set; }
        public int UserID { get; set; }
        [Range(typeof(double), "1", "5")]
        public double? Level { get; set; }
        public virtual Payroll Payroll { get; set; }
        public virtual Function Function { get; set; }
        public virtual User User { get; set; }
    }

    public class User
    {
        public int UserID { get; set; }
        public string NetLogin { get; set; }
        [Required(ErrorMessage = "Employee number is required.")]
        [Display(Name = "Employee Number")]
        [MaxLength(6)] 
        public string EmpNumber { get; set; }
        [Required(ErrorMessage = "First name is required.")]
        [Display(Name = "First Name")]
        [MaxLength(50)] 
        public string Forename { get; set; }
        [Required(ErrorMessage = "Last name is required.")]
        [Display(Name = "Last Name")]
        [MaxLength(50)] 
        public string Surname { get; set; }
        public bool Active { get; set; }
        public virtual ICollection<Permission> Permissions { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace PayPlate.Models
{
    public class JobCode
    {
        public int JobCodeID { get; set; }
        public string Jobcode { get; set; }
        public int DivisionID { get; set; }
        public int AuthChainID { get; set; }
        public int JobID { get; set; }
        public int PensionID { get; set; }
        public int AnalysisGrpID { get; set; }
        public int CostGrpID { get; set; }
        public int ContractID { get; set; }
        public bool AuthJob { get; set; }
        public virtual Division Division { get; set; }
        public virtual AuthChain AuthChain { get; set; }
        public virtual Job Job { get; set; }
        public virtual Pension Pension { get; set; }
        public virtual AnalysisGrp AnalysisGrp { get; set; }
        public virtual CostGrp CostGrp { get; set; }
        public virtual Contract Contract { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class Division
    {
        public int DivisionID { get; set; }
        public string Code { get; set; }
        public string Title { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class AuthChain
    {
        public int AuthChainID { get; set; }
        public string RL01 { get; set; }
        public int RL01Emp { get; set; }
        public string RL02 { get; set; }
        public int RL02Emp { get; set; }
        public string RL03 { get; set; }
        public int RL03Emp { get; set; }
        public string RL04 { get; set; }
        public int RL04Emp { get; set; }
        public string RL05 { get; set; }
        public int RL05Emp { get; set; }
        public string RL06 { get; set; }
        public int RL06Emp { get; set; }
        public string RL07 { get; set; }
        public int RL07Emp { get; set; }
        public string RL08 { get; set; }
        public int RL08Emp { get; set; }
        public string RL09 { get; set; }
        public string RL09Emp { get; set; }
        public string RL10 { get; set; }
        public string RL10Emp { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class Job
    {
        public int JobID { get; set; }
        public string Title { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class Pension
    {
        public int PensionID { get; set; }
        public string Code { get; set; }
        public string Title { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class AnalysisGrp
    {
        public int AnalysisGrpID { get; set; }
        public string Value { get; set; }
        public string Name { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class CostGrp
    {
        public int CostGrpID { get; set; }
        public string Value { get; set; }
        public string Name { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    }

    public class Contract
    {
        public int ContractID { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public double Hours { get; set; }
        public double Weeks { get; set; }
        public int Author { get; set; }
        public DateTime Created { get; set; }
        public string Action { get; set; }
    } 
}

As I have said I am a beginner and I really need some help, I have been looking arround for a few weeks now and can't seem to find a full answer to help show me how to get this working.

My ultimate aim is to implement some of the Extended EF 4.3 fucntions, I have done unitOfWork with Generic repository pattern, how ever I need to be able to audit and be able to view an archived history of changes.

So for exmaple someone adds a new user in, then 5 changes are made by various people and finally the user is deleted. I want to be able to see who did something, what they did, the action they performed (create, update, delete) and finally the date/time they did this.

Additionally I need to know the best way to implement a Business logic layer and where and how I can make functions to return data.

So for example in a student records system, you might want to get the students for a specific Tutor in a specific course. Is it best to keep repeating these queries for every action or sub action e.g. another query could be grades for all students taught by a tutor on a particular course. Or is there a way the I should impletement a GetStudents(TutorID,CourseID) and if so where should these functions go? Would these be generic or is it common you have some generic and some entity specific and if so where do you put them, do they all go in the same class in your DAL folder or do they go in seperate clases or in fact is this what make up your business logic layer?

I know there are a lot of questions here but I have a deadline coming up very soon and need to find a solution to achieve the above.

I really apprciate any help and examples you can offer and here is a link to the nuget package http://efpatterns.codeplex.com/,

Andy

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Your UnitOfWork class is unnessesary complicated and untestable, unreadable. If you are working with Entity Framework then you don't need to create your own UnitOfWork implementation because EF has its own.

What you really need it is a container (IRepositorContainer with a generic Get method for example) which can instantiate (and maybe keep the instance for the lifetime of the AppDomain) the repository. You can use a generic Dictionary (Dictionary<Type, IEntityRepository>) for this and you will not need to hardcode all of your repository into your classes.

\$\endgroup\$
4
  • \$\begingroup\$ Hi Peter, thanks for the advice, I am really new to all this please can you direct me towards an example or provide me with an example of what I need to change and how to use the suggested, based on my example code above? \$\endgroup\$
    – mcinnes01
    Jul 11, 2012 at 9:48
  • \$\begingroup\$ Something like this: dl.dropbox.com/u/15497521/Repo.zip \$\endgroup\$
    – Peter Kiss
    Jul 11, 2012 at 17:04
  • \$\begingroup\$ Thanks Peter that was very helpful, I am looking through my database patterns to see where I can clean things up a little. Also you have an IObjectRepository, do you have any examples of the type of thing you would put in here? And how would you recommend working with both generic and specific database actions. E.g. like you get() action, how would you structure having specifics like maybe GetUserEmail(int UserID)? \$\endgroup\$
    – mcinnes01
    Jul 19, 2012 at 15:34
  • \$\begingroup\$ The IObjectRepository interface only needed to store the repositories in the dictionary nothing more. If you want a GetUserEmail(int uid) method you have the create a specific repo like the ProductRepository in my example. \$\endgroup\$
    – Peter Kiss
    Jul 19, 2012 at 18:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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