четверг, 26 декабря 2013 г.

Использование паттернов Unit of work и Generic Repository c Entity Framework 5.0

Использование паттернов Unit of work и Generic Repository c Entity Framework 5.0
Паттерн Unit of Work, по сути, нужен для консолидации всех методов, которые работают с базой данных. С его помощью можно улучшить контроль над изменением данных в БД, а также оптимизировать использование БД при обработке нескольких запросов одновременно. Использование Generic Repository упростит работу с EF Entities.
Создаем интерфейс IRepository, который описывает все необходимые операции с БД:
public interface IRepository<TEntity>  where TEntity : class
    {
        IEnumerable<TEntity> Get();
        TEntity GetById(object id);
        void Insert(TEntity entity);
        void Delete(object id);
        void Delete(TEntity entityToDelete);
        void Update(TEntity entityToUpdate);
    }

Теперь создадим класс GenericRepository, реализующий этот интерфейс:
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        internal IntraWebEntities Context;
        internal DbSet<TEntity> DbSet;

        public GenericRepository(IntraWebEntities context)
        {
            Context = context;
            DbSet = context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get()
        {
            IQueryable<TEntity> query = DbSet;
            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);
            DbSet.Remove(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;
        }
    }
Теперь перейдем к созданию класса UnitOfWork:
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        internal IntraWebEntities Context;
        internal DbSet<TEntity> DbSet;

       public class UnitOfWork : IDisposable
    {
        private readonly IntraWebEntities _context = new IntraWebEntities();
        private IRepository<User> _userRepository;
        

        public IRepository<User> UserRepository
        {
            get { return _userRepository ?? (_userRepository = new GenericRepository<User>(_context)); }
        }

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

        private bool _disposed;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            _disposed = true;
        }


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

    }

Так как EF context реализует интерфейс IDisposable, то и UnitOfWork должен его реализовать. Тут показана всего одна конкретная реализация репозитория для сущности User, остальные репозитории добавляются аналогично. Для того чтобы постоянно работать с одним экземпляром Unit of Work в приложении ASP.NET MVC был создан BaseController, от которого будут наследоваться все остальные контроллеры:
public abstract class BaseController : Controller
    {  
        private UnitOfWork _unitOfWork;
        public UnitOfWork UnitOfWork
        {
            get { return _unitOfWork ?? (_unitOfWork = new UnitOfWork()); }
        }
}

public class UserController : BaseController
    {
        [AllowAnonymous]
        public ActionResult Index()
        {
            var users = UnitOfWork.UserRepository.Get().ToList();
            return View(users);
        }
}

Комментариев нет:

Отправить комментарий