Je reçois une erreur étrange "impossible de convertir IStudentContext en TestStudentContext" lorsque vous essayez de tester un référentiel générique en C#. Il semble que j'ai besoin de réimplémenter .Set() dans mon interface, n'est-ce pas? Un peu de code omis pour la brièveté mais voici la configuration de base. Pardonne le gros bloc de code j'ajouterai du contexte supplémentaire en bas!Étrange erreur d'interface/TContext lors du test de l'interface générique
IStudentContext.cs
public interface IStudentContext : IDisposable
{
Database Database { get; }
// Irrelevant tables omitted
DbSet<Class> Classes { get; set; }
int SaveChanges();
Task<int> SaveChangesAsync();
}
StudentContext.cs
public class StudentContext : DbContext, IStudentContext
{
public StudentContext() : base("name=StudentContext") {}
// Irrelevant tables omitted
public virtual DbSet<Class> Classes { get; set; }
}
TestStudentContext.cs
public class TestStudentContext : DbContext, IStudentContext
{
public TestStudentContext(DbConnection connection) : base(connection, contextOwnsConnection: true) {}
// Irrelevant tables omitted
public virtual DbSet<Class> Classes { get; set; }
}
EntityFrameworkReadOnlyRepository.cs
public class EntityFrameworkReadOnlyRepository<TContext> : IGenericReadOnlyRepository where TContext : DbContext, IStudentContext
{
protected readonly TContext Context;
public EntityFrameworkReadOnlyRepository(TContext context)
{
Context = context;
}
// Irrelevant generic repo methods omitted
public IEnumerable<TEntity> Get<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string include = null, int? skip = null, int? take = null)
{
return GetQueryable(filter, orderBy, include, skip, take).ToList();
}
protected virtual IQueryable<TEntity> GetQueryable<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string include = null, int? skip = null, int? take = null)
{
include = include ?? string.Empty;
IQueryable<TEntity> query = Context.Set<TEntity>();
if (filter != null)
query = query.Where(filter);
query = include.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Aggregate(query, (current, property) => current.Include(property));
if (orderBy != null)
query = orderBy(query);
if (skip.HasValue)
query = query.Skip(skip.Value);
if (take.HasValue)
query = query.Take(take.Value);
return query;
}
}
StudentRepositoryTests.cs
public class StudentRepositoryTests
{
private IStudentContext Context { get; set; }
[TestInitialize]
public void Initialize()
{
Context = new TestStudentContext(Effort.DbConnectionFactory.CreateTransient());
}
[TestMethod]
public void GetClasses_OrdersCorrectly()
{
// Calls to Context.Classes.Add() to set up DB omitted
Context.SaveChanges();
var repository = new EntityFrameworkReadOnlyRepository<TestStudentContext>(Context);
var results = repository.Get<Classes>().ToArray();
// Assertions omitted
}
}
Comme écrit, je reçois une erreur sur Context
dans la ligne var repository
de ma classe de test. L'erreur indique Argument 1: cannot convert from 'IStudentContext' to 'TestStudentContext'
. Si je change cette ligne à var repository = new EntityFrameworkReadOnlyRepository<IStudentContext>(Context);
, je reçois une erreur The type 'IStudentContext' cannot be used as type parameter 'TContext' in the generic type or method 'EntityFrameworkReadOnlyRepository<TContext>'. There is no implicit reference conversion from 'IStudentContext' to 'System.Data.Entity.DbContext'.
On dirait que si je mets en œuvre DbSet pour toutes mes tables de base de données dans IStudentContext
que pourrait résoudre le problème, mais qui se sent comme si je réimplémentant beaucoup de code juste pour être en mesure de tester quelque chose, donc je pense qu'il y aurait une façon plus simple de le faire.
Le type 'DbContext' est une implémentation d'un modèle UoW et le type' DbSet 'est une implémentation d'un modèle Repository. Pourquoi réemballer ces types dans votre propre implémentation du même modèle? Vous n'ajoutez rien de valeur, juste plus de code et une mauvaise abstraction qui résulte en un code plus difficile à lire, à déboguer et à utiliser. –
Igor
@Igor Je ne suis pas marié à cette implémentation - quelle est votre suggestion pour une meilleure implémentation? Nous sommes en train d'écrire une API orientée public et ma pensée initiale était les entités EF, un référentiel au-dessus, et un service métier supérieur (transformant les réponses du référentiel dans la structure de données qui sera retournée à l'utilisateur). –
Je recommande de consommer le DbContext directement dans les services métier. – Igor