The short example about Entity Framework 4 CTP4 - Part 2

Part 2: Repository and Unit of Work on Entity Framework 4

  • Create the repository for persistence ignorance

Up to now, I very love the Persistence Ignorance. So what is it? I remembered that I usually built the Data Access Layer for access Database in the past. That is make your layer is coupling with the Database. So it is not good if you change database, change something else. So what do you think if we don’t need to know about it? Just tell the class that “I want to make something, and don’t care what happen in the behind scene.” It’s really good, and that is a place where Repository pattern jumps into. For more information, go to http://martinfowler.com/eaaCatalog/repository.html. I don’t want to speak more about it. Now we shall continue on my example. The first thing, we must to build is a IRepository interface for making a contract.

    public interface IRepository<T> where T : IEntity
    {
    }

IRepository is constraint on T generic type and must be an IEntity. Now I want to separate with 2 Repositories that do specific jobs. At here, I divided 2 Repositories with 2 contracts are: ICommandRepository and IQueryRepository. ICommandRepository contains all actions about CRUD, and IQueryRepository contains all actions about query data. That is it.

    public interface ICommandRepository<T> : IRepository<T> where T : IEntity
    {
        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        T GetById(int id);

        /// <summary>
        /// Adds the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        T Add(T entity);

        /// <summary>
        /// Updates the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        void Update(T entity);

        /// <summary>
        /// Deletes the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        void Delete(T entity);

        /// <summary>
        /// Deletes the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        void Delete(int id);

        /// <summary>
        /// Units the of work.
        /// </summary>
        /// <returns></returns>
        IUnitOfWork UnitOfWork();
    }

And,

    public interface IQueryRepository<T> : IRepository<T> where T : IEntity
    {
        /// <summary>
        /// Gets all.
        /// </summary>
        /// <returns></returns>
        IEnumerable<T> GetAll();

        /// <summary>
        /// Gets the specified where.
        /// </summary>
        /// <param name="where">The where.</param>
        /// <returns></returns>
        IEnumerable<T> Get(Func<T, bool> where);
    }

I also have a base Repository for re-use all things that you think it can shared for all Repository used.

    public abstract class BaseRepository<T> : IDisposable
    {
        private DbContext _dbContext;

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseRepository&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="databaseFactory">The database factory.</param>
        public BaseRepository(IDatabaseFactory databaseFactory)
        {
            Contract.Assert(databaseFactory != null"DatabaseFactory is null");

            DatabaseFactory = databaseFactory;
        }

        /// <summary>
        /// Gets or sets the database factory.
        /// </summary>
        /// <value>The database factory.</value>
        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the db context.
        /// </summary>
        /// <value>The db context.</value>
        protected DbContext DbContext
        {
            [DebuggerStepThrough]
            get
            {
                return _dbContext ?? (_dbContext = DatabaseFactory.Get());
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (DbContext != null)
                GC.SuppressFinalize(DbContext);

            if (DatabaseFactory != null)
                GC.SuppressFinalize(DatabaseFactory);
        }
    }
Now we can implement the CategoryRepository as below:
    public interface ICategoryRepository : ICommandRepository<Category>, IQueryRepository<Category>
    {
    }
    public class CategoryRepository : BaseRepository<Category>, ICategoryRepository
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryRepository"/> class.
        /// </summary>
        /// <param name="databaseFactory">The database factory.</param>
        public CategoryRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }

        /// <summary>
        /// Units the of work.
        /// </summary>
        /// <returns></returns>
        public IUnitOfWork UnitOfWork()
        {
            return DbContext as CSPDbContext;
        }

        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public Category GetById(int id)
        {
            Contract.Assert(DbContext != null"DbContext is null");

            var temp = DbContext as CSPDbContext;
            return (temp).Categories.Where<Category>(x => x.Id == id).FirstOrDefault<Category>();
        }

        /// <summary>
        /// Adds the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        public Category Add(Category entity)
        {
            Contract.Assert(DbContext != null"DbContext is null");

            var temp = DbContext as CSPDbContext;
            temp.Categories.Add(entity);

            return entity;
        }

        ...


    }
  • Unit of Work on EF4 

This is a hard pattern in EF4, so I will don’t explain about it. I just gave you a reference to read it, and I also implemented according to this link

http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx

This is my code:

    public interface IUnitOfWork
    {
        /// <summary>
        /// Saves this instance.
        /// </summary>
        void Save();
    }
 
    public partial class CSPDbContext : DbContextIUnitOfWork
    {
        ...
        /// <summary>
        /// Saves this instance.
        /// </summary>
        public void Save()
        {
            SaveChanges();
        }
    }

I gave the CSPDbContext implementing the IUnitOfWork contract, and

public class CategoryRepository : BaseRepository<Category>, ICategoryRepository
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryRepository"/> class.
        /// </summary>
        /// <param name="databaseFactory">The database factory.</param>
        public CategoryRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }

        /// <summary>
        /// Units the of work.
        /// </summary>
        /// <returns></returns>
        public IUnitOfWork UnitOfWork()
        {
            return DbContext as CSPDbContext;
        }
        ...
    }

Now I do unit testing for CategoryRepository as:

        [TestMethod()]
        public void GetAllTesting()
        {
            var result = CategoryRepository.GetAll();
            Assert.IsNotNull(result);
        }
        [TestMethod()]
      public void AddCategoryTesting()
        {
            var entity = CategoryRepository.Add(new CallStoreProc.Data.Entity.Category()
            {
                Name = "test",
                IsDelete = false,
                CreatedDate = DateTime.Now,
                Description = "test"
            });

            Assert.IsNotNull(entity);
            Assert.AreEqual(entity.Name, "test");
            Assert.AreEqual(entity.IsDelete, false);
        }

Unit testing for UnitOfWork:

        [TestMethod()]
        public void UnitOfWorkTesting()
        {
            var uow = CategoryRepository.UnitOfWork();

            var entity1 = CategoryRepository.Add(new CallStoreProc.Data.Entity.Category()
            {
                Name = "test3",
                IsDelete = false,
                CreatedDate = DateTime.Now,
                Description = "test3"
            });

            var entity2 = CategoryRepository.Add(new CallStoreProc.Data.Entity.Category()
            {
                Name = "test4",
                IsDelete = false,
                CreatedDate = DateTime.Now,
                Description = "test4"
            });

            uow.Save();
        }
 

Part 1: Step up ADO.NET Entity Framework 4 CTP4

Part 3: Invoke store procedure in ADO.NET Entity Framework 4

3 Comments

  • Can you show CategoryRepository.Update(Category)? I've not yet found an EF CTP4 walk-through or tutorial that updates an existing entity.

  • @Benjamin: You only get the entity that you want to updating and fill with the data. Finally, you attach it into the ObjectContext, and call unit of work for save changes. Thanks for your comment, man!

  • Dear thangchuang,
    Can you give us a source code download of your example ?
    It's really helpful for me. Thanks.

Comments have been disabled for this content.