我做我所做的最终目的是为DbContext
提供一些缓存功能。为了实现这一点,我试图通过覆盖上下文中的DbSet
方法来扩展默认的Set<T>()
功能,并返回直接从通用DbSet
类派生的类型的对象。像这样:
public class Context : DbContext
{
...
public override DbSet<TEntity> Set<TEntity>()
{
//var set = base.Set<TEntity>();
var set = new XxSet<TEntity>();
return set;
}
}
class XxSet<TEntity> : System.Data.Entity.DbSet<TEntity>
where TEntity : class
{
public override TEntity Find(params object[] keyValues)
{
return base.Find(keyValues);
}
}
看起来很简单,但当我对此进行测试时,EF给了我一个错误:
成员'IQueryable.Provider'尚未在类型上实现 'XxSet'1'继承自'DbSet'1'。为'DbSet'1'测试双打 必须提供使用的方法和属性的实现。
它要求我实现IQueryable接口。那是我看到的,但为什么呢?它不应该已经在基类中实现了吗?
我想它必须,否则,Set<T>()
方法的基本功能如何工作,它返回由System.Data.Entity.DbSet<TEntity>
类型实例化的对象。
我在这里错过了什么吗?
顺便说一句。我知道有关创建内存中DbSet的Microsoft示例。我只是想明白为什么我不能这么简单。
答案 0 :(得分:0)
我不知道为什么它不起作用,这看起来像本来可以做的但是实体不喜欢它,在这个链接中:
NSubstitute DbSet / IQueryable<T>
有类似的错误,抱歉,如果它根本没有帮助你 -
那是答案吗?很高兴它帮助了你。
答案 1 :(得分:0)
我在实现继承IDbSet的接口的类中遇到了一些问题。这是因为所有(或至少大部分)IQueryable方法都没有在DbSet中实现,而是Queryable类的扩展方法。大多数模拟框架都不能模拟静态扩展方法。我通过将方法添加到我的派生接口并在我的类中实现了方法克服了这个问题:IDerivedDbSet按照这些例子:
public IQueryable<T> Where(Expression<Func<T, bool>> predicate)
{
return this._dbSet.Where(predicate);
}
public bool Any(Expression<Func<T, bool>> predicate)
{
return this._dbSet.Any(predicate);
}
测试使用这些方法的位置有点脏,因为您现在必须模拟该方法,而不是依赖于在模拟注入的IQueryable上实际执行的扩展。这是一个例子:
this._context = Substitute.For<IDerivedContext>();
this._permissionSet = Substitute.For<IDerivedSet<Permission>> ();
this._permission1 = new Permission
{
UserID = 1,
MenuID = 26,
PermissionAllow = true
};
var queryable = (new List<Permission> { this._permissionLink1 }).AsQueryable();
this._permissionSet.Any(Arg.Any<Expression<Func<Permission, bool>>>()).Returns(x => queryable.Any((Expression<Func<Permission, bool>>)x[0]));
var result = this._permissionsProvider.HasPermissionToSomething(this._context, 1);
Assert.IsTrue(result);
脏位是IDerivedDbSet.Any方法的表达式参数然后用作直接在queryable上调用的Queryable.Any扩展方法的表达式参数。它并不好,因为它假设两个Any方法做同样的事情,但它允许我模拟实现的实际查询并断言测试类在此基础上返回正确的结果。如果我在测试类方法中更改查询,则测试失败。