Generic repository pattern and Unit of work with Entity framework

时间:2023-03-09 21:17:33
Generic repository pattern and Unit of work with Entity framework

原文 Generic repository pattern and Unit of work with Entity framework

Repository pattern is an abstraction layer between your business logic layer and data access layer. This abstract layer contains methods to server data from data layer to business layer. Now, changes in your data layer cannot affect the business layer directly.

For more information about repository pattern or unit of work visit this article. Below is my approach how to implement repository pattern and unit of work with entity framework.

1. Create IGenericRepository interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public interface IGenericRepository<TEntity>
{
    /// <summary>
    /// Get all entities from db
    /// </summary>
    /// <param name="filter"></param>
    /// <param name="orderBy"></param>
    /// <param name="includes"></param>
    /// <returns></returns>
    List<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        params Expression<Func<TEntity, object>>[] includes);
    /// <summary>
    /// Get query for entity
    /// </summary>
    /// <param name="filter"></param>
    /// <param name="orderBy"></param>
    /// <returns></returns>
    IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null);
    /// <summary>
    /// Get single entity by primary key
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    TEntity GetById(object id);
    /// <summary>
    /// Get first or default entity by filter
    /// </summary>
    /// <param name="filter"></param>
    /// <param name="includes"></param>
    /// <returns></returns>
    TEntity GetFirstOrDefault(
        Expression<Func<TEntity, bool>> filter = null,
        params Expression<Func<TEntity, object>>[] includes);
    /// <summary>
    /// Insert entity to db
    /// </summary>
    /// <param name="entity"></param>
    void Insert(TEntity entity);
    /// <summary>
    /// Update entity in db
    /// </summary>
    /// <param name="entity"></param>
    void Update(TEntity entity);
    /// <summary>
    /// Delete entity from db by primary key
    /// </summary>
    /// <param name="id"></param>
    void Delete(object id);
}

2. Create GenericRepository class to implement interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    private DbContext context;
    private DbSet<TEntity> dbSet;
    public GenericRepository(DbContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }
    public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, params Expression<Func<TEntity, object>>[] includes)
    {
        IQueryable<TEntity> query = dbSet;
        foreach (Expression<Func<TEntity, object>> include in includes)
            query = query.Include(include);
        if (filter != null)
            query = query.Where(filter);
        if (orderBy != null)
            query = orderBy(query);
        return query.ToList();
    }
    public virtual IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
    {
        IQueryable<TEntity> query = dbSet;
        if (filter != null)
            query = query.Where(filter);
        if (orderBy != null)
            query = orderBy(query);
        return query;
    }
    public virtual TEntity GetById(object id)
    {
        return dbSet.Find(id);
    }
    public virtual TEntity GetFirstOrDefault(Expression<Func<TEntity, bool>> filter = null, params Expression<Func<TEntity, object>>[] includes)
    {
        IQueryable<TEntity> query = dbSet;
        foreach (Expression<Func<TEntity, object>> include in includes)
            query = query.Include(include);
        return query.FirstOrDefault(filter);
    }
    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }
    public virtual void Update(TEntity entity)
    {
        dbSet.Attach(entity);
        context.Entry(entity).State = EntityState.Modified;
    }
    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }
}

3. Create IUnitOfWork interface

1
2
3
4
5
public interface IUnitOfWork
{
    IGenericRepository<Model> ModelRepository { get; }
    void Save();
}

4. Create UnitOfWork class to implement interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class UnitOfWork : IUnitOfWork, System.IDisposable
{
    private readonly MyDatabaseContext _context;
    private IGenericRepository<Model> _modelRepository;
    public UnitOfWork(MyDatabaseContext context)
    {
        _context = context;
    }
    public IGenericRepository<Model> ModelRepository
    {
        get { return _modelRepository ?? (_modelRepository = new GenericRepository<Model>(_context)); }
    }
    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);
        System.GC.SuppressFinalize(this);
    }
}

5. Usage in controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class HomeController : Controller
{
    private IUnitOfWork _unitOfWork;
    public HomeController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    //
    // GET: /Home/
    public ActionResult Index()
    {
        // get all models (all properties)
        List<Model> modelList = _unitOfWork.ModelRepository.Get(m => m.FirstName == "Jan" || m.LastName == "Holinka", includeProperties: "Account");
        // get all models (some properties)
        List<ModelDto> modelDtoList = _unitOfWork.UserRepository
            .Query(x => x.FirstName == "Jan" || x.LastName == "Holinka")
            .Select(x => new ModelDto
            {
                FirstName = x.FirstName,
                LastName = x.LastName
            })
            .ToList();
            return View("Index");
        }
        // show list of models in view
        return View(modelList);
    }
}
public class ModelDto
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

That's all.