Entity Framework 4 CTP 4 / CTP 5 Общий шаблон репозитория и модульное тестирование

Я играю с последней версией Entity Framework CTP 5 и создаю простой блог asp.net MVC, где у меня есть только две таблицы: Post и Comments. Это делается полностью в POCO, мне просто нужна помощь в части DbContext, где мне нужно, чтобы она была тестируемой модулем (используя IDbSet?), И мне нужен простой / универсальный шаблон репозитория для добавления, обновления, удаления, извлечения. Любая помощь приветствуется.

Благодарю.

3 ответа

Решение

Начнем с DbContext, создайте новый файл с именем Database.cs:

Database.cs

public class Database : DbContext
    {

        private IDbSet<Post> _posts;

        public IDbSet<Post> Posts {
            get { return _posts ?? (_posts = DbSet<Post>()); }
        }

        public virtual IDbSet<T> DbSet<T>() where T : class {
            return Set<T>();
        }
        public virtual void Commit() {
            base.SaveChanges();
        }
}

Определите IDatabaseFactory и реализуйте его с помощью DatabaseFactory:

IDatabaseFactory.cs

public interface IDatabaseFactory : IDisposable
    {
        Database Get();
    }

DatabaseFactory.cs

public class DatabaseFactory : Disposable, IDatabaseFactory {
        private Database _database;
        public Database Get() {
            return _database ?? (_database = new Database());
        }
        protected override void DisposeCore() {
            if (_database != null)
                _database.Dispose();
        }
    }

Одноразовый метод расширения:

Disposable.cs

public class Disposable : IDisposable
    {
        private bool isDisposed;

        ~Disposable()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if(!isDisposed && disposing)
            {
                DisposeCore();
            }

            isDisposed = true;
        }

        protected virtual void DisposeCore()
        {
        }
    }

Теперь мы можем определить наш IRepository и нашу RepositoryBase

IRepository.cs

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    T GetById(long Id);
    IEnumerable<T> All();
    IEnumerable<T> AllReadOnly();
}

RepositoryBase.cs

public abstract class RepositoryBase<T> where T : class
    {
        private Database _database;
        private readonly IDbSet<T> _dbset;
        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            _dbset = Database.Set<T>();
        }

        protected IDatabaseFactory DatabaseFactory
        {
            get; private set;
        }

        protected Database Database
        {
            get { return _database ?? (_database = DatabaseFactory.Get()); }
        }
        public virtual void Add(T entity)
        {
            _dbset.Add(entity);
        }

        public virtual void Delete(T entity)
        {
            _dbset.Remove(entity);
        }

        public virtual void Update(T entity)
        {
            _database.Entry(entity).State = EntityState.Modified;
        }
        public virtual T GetById(long id)
        {
            return _dbset.Find(id);
        }

        public virtual IEnumerable<T> All()
        {
            return _dbset.ToList();
        }
        public virtual IEnumerable<T> AllReadOnly()
        {
            return _dbset.AsNoTracking().ToList();
        }
    }

Теперь вы можете создать свой IPostRepository и PostRepository:

IPostRepository.cs

     public interface IPostRepository : IRepository<Post>
        {
            //Add custom methods here if needed
            Post ByTitle(string title);
        }

PostRepository.cs

    public class PostRepository : RepositoryBase<Post>, IPostRepository
        {
            public PostRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
            {
            }
            public Post ByTitle(string title) {
                return base.Database.Posts.Single(x => x.Title == title);
            }
        }

Наконец, UoW:

IUnitOfWork.cs

public interface IUnitOfWork
{
    void Commit();
}

UnitOfWork.cs

private readonly IDatabaseFactory _databaseFactory;
private Database _database;

public UnitOfWork(IDatabaseFactory databaseFactory)
{
    _databaseFactory = databaseFactory;
}

protected Database Database
{
    get { return _database ?? (_database = _databaseFactory.Get()); }
}

public void Commit()
{
    Database.Commit();
}

Использование в вашем контроллере:

private readonly IPostRepository _postRepository;
private readonly IUnitOfWork_unitOfWork;

        public PostController(IPostRepository postRepository, IUnitOfWork unitOfWork)
        {
            _postRepository = postRepository;
            _unitOfWork = unitOfWork;
        }

        public ActionResult Add(Post post) {
            _postRepository.Add(post);
            _unitOfWork.Commit();
        }

Вам нужно будет использовать контейнер IoC, такой как StructureMap, чтобы сделать эту работу. Вы можете установить карту структуры через NuGet или, если вы используете MVC 3, вы можете установить пакет StructureMap-MVC NuGet. (Ссылки ниже)

Структура пакета установки Map.MVC4

Структура пакета установки Map.MVC3

Структура пакета установки пакета

Если у вас есть вопросы, просто дайте мне знать. Надеюсь, поможет.

Мне просто нравится эта глубокая статья о POCO Entity Framework 4, репозитории и шаблонах спецификаций.

http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/

Единственное, что я бы сделал по-другому, - это реализация, то есть выставить IPostRepository на уровне сервиса и иметь поле интерфейса типа IPostService в контроллере как еще один уровень абстракции, но в остальном это хороший пример - хороший пример, Пол,

Другие вопросы по тегам