Unité De Travail & Generic Référentiel avec Entity Framework 5

Je suis en utilisant ASP.NET MVC 4 avec Entity Framework 5. J'ai des classes de modèle et de l'Entité correspond à la carte de tables existantes à ceux des classes de modèle. Tout cela est de l'installation d'amende et fonctionne très bien.

Maintenant, je veux me moquer de ce. J'ai créé Unité De Travail qui prend le DataContext et utilise un Générique Référentiel. Dès que j'ai construit services pour être en mesure d'obtenir des données à partir de plusieurs référentiels à la fois et seulement besoin d'avoir une instance de la DataContext. Cela fonctionne aussi grande.

Maintenant au problème: je veux tester les services, avec des simulations de données. Lorsque je crée l'Unité De Travail de l'instance, je veux être capable d'insérer un DataContext est moqué de la place de la vraie DataContext.

J'ai essayé de créer un IContext de l'interface et de laisser le réel et se moque de DataContext de mettre en œuvre, mais a couru dans des problèmes avec DbSet. J'ai essayé d'utiliser IDbSet et la création d'un FakeDbSet mais sans succès. J'ai aussi lu sur internet que se moquer de la contexte avec IDbSet et à l'aide d'un FakeDbSet est une mauvaise approche.

Avez-vous une idée de ce que serait la meilleure façon d'atteindre cet objectif? Ce que j'ai maintenant, c'est le comportement que je souhaite garder, mais voudrais vraiment être en mesure de se moquer des données à partir du Modèle des classes dans le DataContext.

Je suis conscient de ce que Entity Framework est déjà fourni avec l'Unité De Travail, le comportement et que vous n'avez pas besoin d'ajouter de comportement sur le dessus de cela. Mais je voulais terminer qu'à l'intérieur d'une autre classe qui conserve la trace de tous les dépôts (appelé UnitOfWork classe).

Edit: j'ai écrit deux articles expliquant ma solution avec LINQ et Entity Framework.

http://gaui.is/how-to-mock-the-datacontext-linq/

http://gaui.is/how-to-mock-the-datacontext-entity-framework/

Voici mon code:

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> Find(Expression<Func<T, bool>> predicate);
}

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable
{
    IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
    void Save();
}

Référentiel.cs

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDbContext _context;
    private readonly IDbSet<T> _dbset;

    public Repository(IDbContext context)
    {
        _context = context;
        _dbset = context.Set<T>();
    }

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

    public virtual void Delete(T entity)
    {
        var entry = _context.Entry(entity);
        entry.State = System.Data.EntityState.Deleted;
    }

    public virtual void Update(T entity)
    {
        var entry = _context.Entry(entity);
        _dbset.Attach(entity);
        entry.State = System.Data.EntityState.Modified;
    }

    public virtual T GetById(long id)
    {
        return _dbset.Find(id);
    }

    public virtual IEnumerable<T> All()
    {
        return _dbset;
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
    {
        return _dbset.Where(predicate);
    }
}

UnitOfWork.cs

public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
    private readonly IDbContext _ctx;
    private Dictionary<Type, object> _repositories;
    private bool _disposed;

    public UnitOfWork()
    {
        _ctx = new TContext();
        _repositories = new Dictionary<Type, object>();
        _disposed = false;
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        if (_repositories.Keys.Contains(typeof(TEntity)))
            return _repositories[typeof(TEntity)] as IRepository<TEntity>;

        var repository = new Repository<TEntity>(_ctx);
        _repositories.Add(typeof(TEntity), repository);
        return repository;
    }

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

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

    protected virtual void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            if (disposing)
            {
                _ctx.Dispose();
            }

            this._disposed = true;
        }
    }
}

ExampleService.cs

public class ExampleService
{
    private IRepository<Example> m_repo;

    public ExampleService(IUnitOfWork uow)
    {
        m_repo = uow.GetRepository<Example>();
    }

    public void Add(Example Example)
    {
        m_repo.Add(Example);
    }

    public IEnumerable<Example> getAll()
    {
        return m_repo.All();
    }
}

ExampleController.cs

public IEnumerable<Example> GetAll()
{
    //Create Unit Of Work object
    IUnitOfWork uow = new UnitOfWork<AppDataContext>();

    //Create Service with Unit Of Work attached to the DataContext
    ExampleService service = new ExampleService(uow);

    return service.getAll();
}
  • J'ai aussi eu le même problème que vous avez mentionné. Cependant, vous pouvez poster votre code pour IDbContext et le béton de la classe qui implémente IDbContext? Cela va beaucoup m'aider. Merci à l'avance.
  • http://gaui.is/how-to-mock-the-datacontext-entity-framework/
  • Ne serait-il pas préférable de créer votre UnitOfWork exemple à l'intérieur de votre ExampleService classe à la place de votre contrôleur? De cette façon, votre contrôleur n'a pas besoin de savoir ce que DbContext il a besoin, il le laisse pour le service.
  • C'est juste une préférence vraiment. Si vous voulez avoir beaucoup de services à l'aide de la même uow objet, vous devez le faire à l'extérieur du service.
  • Je dirais que, si la consommation de votre service à distance, que vous ne voulez pas le uow existant à l'extérieur du service. Vous ne voulez pas ouvrir les transactions/connexions traîner dans un environnement sans état. Si le consommateur n'est pas à distance, cela peut ne pas être un problème.
  • Pourquoi avez-vous appelé SaveChanges sur chaque opération dans Repository classe? Ce ne sera pas sûr pour les transactions

InformationsquelleAutor Gaui | 2013-05-23