Подтвердить что ты не робот

Entity Framework 4 CTP 4/CTP 5 Общий шаблон хранилища и единица тестирования

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

Спасибо.

4b9b3361

Ответ 1

Начните с 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. (Ссылки ниже)

Install-Package StructureMap.MVC4

Install-Package StructureMap.MVC3

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

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

Ответ 3

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