简体   繁体   English

EF6:从派生的DbSet获取数据

[英]EF6: getting data from derived DbSet

My ultimate reason of doing what I do is to provide some caching capabilities to the DbContext . 我做我工作的最终目的是为DbContext提供一些缓存功能。 In order to achieve this, I'm trying to extend default DbSet functionality by overriding Set<T>() method in the context, and returning object of type that is directly derived from general DbSet class. 为了实现此目的,我试图通过在上下文中重写Set<T>()方法并返回直接从常规DbSet类派生的类型的对象来扩展默认的DbSet功能。 Like this: 像这样:

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);
    }
}

Looks clear and simple, but when I run my tests on this, EF gives me an error: 看起来清晰而简单,但是当我对此进行测试时,EF给我一个错误:

The member 'IQueryable.Provider' has not been implemented on type 'XxSetˊ1' which inherits from 'DbSetˊ1'. 成员'IQueryable.Provider'尚未在继承自'DbSetˊ1'的类型'XxSetˊ1'上实现。 Test doubles for 'DbSetˊ1' must provide implementations of methods and properties that are used. “ DbSetˊ1”的测试双精度必须提供所用方法和属性的实现。

It asks me to implement IQueryable interface. 它要求我实现IQueryable接口。 That's I see, but why? 我知道,但是为什么呢? Shouldn't it already be implemented in the base class? 它应该已经在基类中实现了吗? I guess it must, otherwise, how would work the base functionality of Set<T>() method, which is returning object instantiated by System.Data.Entity.DbSet<TEntity> type. 我想这一定是必须的,否则Set<T>()方法的基本功能Set<T>()如何工作,该方法将返回由System.Data.Entity.DbSet<TEntity>类型实例化的对象。

Am I missing something here? 我在这里想念什么吗?

BTW. BTW。 I know about Microsoft example of creating in-memory DbSets. 我知道有关创建内存中DbSet的Microsoft示例。 I just want to understand why can't I do this simple way. 我只想了解为什么我不能做这种简单的方法。

I don't know why it dosen't work, this looks like something that could have been done but entity dosen't like it, in this link : 我不知道为什么它不起作用,这看起来像可以完成但实体不喜欢的事情,在此链接中:

NSubstitute DbSet / IQueryable<T> NSubstitute DbSet / IQueryable <T>

there are similar errors, sorry if it dosen't help you at all – 有类似的错误,很抱歉,如果它根本无法帮助您–

It was the answer then ? 那是答案吗? Glad it helped you. 很高兴为您提供帮助。

I've had some of these issues with classes implementing interfaces inheriting IDbSet. 我在实现继承IDbSet的接口的类中遇到了一些问题。 It's because all (or at least most of) the IQueryable methods are not implemented in the DbSet, but are extension Methods of the Queryable class. 这是因为所有(或至少大多数)IQueryable方法都没有在DbSet中实现,而是Queryable类的扩展方法。 Most mocking frameworks cannot mock static extension methods. 大多数模拟框架不能模拟静态扩展方法。 I overcame the problem by adding the method to my derived interface and implemented the methods in my class : IDerivedDbSet as per these examples: 我通过将方法添加到派生的接口并在我的类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);
    }

Testing where these methods are used is a bit dirty though, because you now have to mock the method instead of relying on the extension actually executing on an IQueryable injected by a mock. 但是,测试使用这些方法的位置有点脏,因为您现在必须模拟该方法,而不是依赖模拟在注入的IQueryable上实际执行的扩展。 Here's an example: 这是一个例子:

 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);

The dirty bit is that the expression parameter for the IDerivedDbSet.Any method is then used as the expression parameter for the Queryable.Any extension method invoked on queryable directly. 肮脏的是,然后将IDerivedDbSet.Any方法的expression参数用作直接在queryable上调用的Queryable.Any扩展方法的expression参数。 It's not great, because it assumes that the two Any methods do the same thing, but it does allow me mock the actual query implemented and assert that the tested class is returning the correct result on that basis. 这不是很好,因为它假定两个Any方法都做同样的事情,但是它确实允许我模拟实际实现的查询并断言被测试的类在此基础上返回了正确的结果。 If I change the query in the tested class method, the test fails. 如果我在已测试的类方法中更改查询,则测试将失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM