Zakaria.d
Zakaria.d

Reputation: 168

Transaction with the Repository Design patterns

I developed an ASP.NET MVC application to manage projects, using Entity Framework 6.0 and the Repository design pattern. Now I want to integrate transactions in order to insure that some insert/update database operations respect the ACID principal and especially the atomicity principal.

Below is a snippets of my Generic repository :

1. Generic repository interface

    public interface IGenericRepository<T> : IRepository  where T : BaseEntity
    {
        void Create(T entity);
        void Delete(T entity);
        IEnumerable<T> GetAll();
        void Update(T entity);
    }

2. Generic repository class

public abstract class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
        {
            protected IContext _context;
            protected IDbSet<T> _dbset;

            public GenericRepository(IContext context)
            {
                _context = context;
                _dbset = _context.Set<T>();
            }


            public virtual void Create(T entity)
            {
                if (entity == null)
                {
                    throw new ArgumentNullException("entity");
                }

                _dbset.Add(entity);
                _context.SaveChanges();
            }


            public virtual void Update(T entity)
            {
                if (entity == null) throw new ArgumentNullException("entity");
                _context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
                _context.SaveChanges();
            }

            public virtual void Delete(T entity)
            {
                if (entity == null) throw new ArgumentNullException("entity");
                _dbset.Remove(entity);
                _context.SaveChanges();
            }

            public virtual IEnumerable<T> GetAll()
            {
                return _dbset.AsEnumerable<T>();
            }
        }

3. My Icontext implementation

public interface IContext
    {
        IDbSet<Projet> Projects { get; set; }     
        IDbSet<Task> Tasks{ get; set; }
        IDbSet<Entite> Entities { get; set; }

        DbSet<TEntity> Set<TEntity>() where TEntity : class;
        DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;

        int SaveChanges();
    }

4. The Project Entity

public class ProjectRepository : GenericRepository<Projet>, IProjectRepository
    {

        IContext _context;

        public ProjectRepository(IContext context) : base(context)
        {
            _context = context;
            _dbset = _context.Set<Projet>();
        }

        public Projet GetProjectById(int Id) 
        {
            return _dbset.FirstOrDefault(x=>x.Id == Id);
        }

    }

So, what I want to do, is to have transactions work with the model above. For example, when a project is created with his tasks I want to use a transaction to save the Project and the Task entities, so I'm sure that the insert of theses entities would be an atomic operation.

thanks for your help and suggestions.

Upvotes: 3

Views: 5592

Answers (1)

Houssam Hamdan
Houssam Hamdan

Reputation: 908

Usually, your repositories are injected into engine / service classes. I will assume we have a ProjectEngine.cs where ProjectRepo and TaskRepo are injected. The code will look as follows:

     public class ProjectEngine : IProjectEngine
        {
            IProjectRepository projectRepository;
            ITaskRepository taskRepository;

            public ProjectEngine(
                IProjectRepository ProjectRepository,
                ITaskRepository TaskRepository)
            {
                projectRepository = ProjectRepository;
                taskRepository = TaskRepository;
            }

            public void CreateProject(CreateProjectRequest createProjectRequest)
            {

            using (TransactionScope scope = new TransactionScope())
                    {

                       // these operations are atomic since they below to same transactionscope
                        projectRepository.Add([project]);
                        taskRepository.Add([tasks]);
                        // data will not be affected until complete operation is called. Any database exception would rollback the transaction.
                        scope.Complete();
                    }

              } 

         }

To recap, the best way to do that is by including multiple repositories operations within same transactionscope.

Upvotes: 6

Related Questions