【问题标题】:IDbAsyncEnumerable not implementedIDbAsyncEnumerable 未实现
【发布时间】:2014-12-05 10:14:32
【问题描述】:

我正在尝试使用 FakeDbSet 制作 FakeDbContext 以进行单元测试。

但我收到以下错误(见下文)。我正在扩展 DbSet,所以通常应该实现 IDbAsyncEnumerable。而且当我实现它时,它说它没有用。

例外:

System.InvalidOperationException:源 IQueryable 没有 实施 IDbAsyncEnumerable。仅有的 实现 IDbAsyncEnumerable 的源可用于实体 框架异步操作。有关更多详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=287068.

FakeDbSet 类:

public abstract class FakeDbSet<TEntity> : DbSet<TEntity>, IEnumerable<TEntity>, IQueryable, IDbAsyncEnumerable<TEntity> where TEntity : Entity, new()
{
    #region Private Fields
    private readonly ObservableCollection<TEntity> _items;
    private readonly IQueryable _query;
    #endregion Private Fields

    protected FakeDbSet()
    {
        _items = new ObservableCollection<TEntity>();
        _query = _items.AsQueryable();
    }

    public Expression Expression { get { return _query.Expression; } }

    public Type ElementType { get { return _query.ElementType; } }

    public IQueryProvider Provider { get { return _query.Provider; } }

    public override TEntity Add(TEntity entity)
    {
        _items.Add(entity);
        return entity;
    }

    public override TEntity Remove(TEntity entity)
    {
        _items.Remove(entity);
        return entity;
    }

    public override TEntity Attach(TEntity entity)
    {
        switch (entity.ObjectState)
        {
            case ObjectState.Modified:
                _items.Remove(entity);
                _items.Add(entity);
                break;

            case ObjectState.Deleted:
                _items.Remove(entity);
                break;

            case ObjectState.Unchanged:
            case ObjectState.Added:
                _items.Add(entity);
                break;

            default:
                throw new ArgumentOutOfRangeException();
        }
        return entity;
    }

    public override TEntity Create() { return new TEntity(); }

    public override TDerivedEntity Create<TDerivedEntity>() { return Activator.CreateInstance<TDerivedEntity>(); }

    public override ObservableCollection<TEntity> Local { get { return _items; } }

    IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    Type IQueryable.ElementType
    {
        get { return _items.AsQueryable().ElementType; }
    }

    Expression IQueryable.Expression
    {
        get { return _items.AsQueryable().Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _items.AsQueryable().Provider; }
    }

这是代码的要点。在要点的最后一个文件中,这就是发生错误的地方。 Gist code

【问题讨论】:

标签: c# entity-framework


【解决方案1】:

在我的情况下,异常是由于使用了错误的 ToListAsync 扩展名引起的。

它来自:

using System.Data.Entity;

而不是

using Microsoft.EntityFrameworkCore;

更改命名空间修复了错误。

【讨论】:

  • 这也是我的问题!作为记录,我发现将漂亮的抽象拆分为具体的 EFCore 实现真的很讨厌,并迫使 DEV 绑定到 EFCore ............
  • 这解决了我在这个问题上的问题!
  • 这应该是一个公认的答案——我花了很长时间才找到这个。谢谢
  • 每次都能得到我。
  • 再次用谷歌搜索同样的问题,发现我已经支持你的答案并且它再次帮助了我!不能投票两次,抱歉
【解决方案2】:

异常消息 (http://go.microsoft.com/fwlink/?LinkId=287068) 提供的链接中明确提到了您的情况。缺少的成分是您应该从 Provider 属性返回的 IDbAsyncQueryProvider。

只需浏览链接即可到达the boilerplate implementation

我可以补充一点,我只是引用基本的短语:

为了使用异步查询,我们需要做更多的工作。如果我们尝试将 Moq DbSet 与 GetAllBlogsAsync 方法一起使用,我们会得到以下异常:

System.InvalidOperationException:源 IQueryable 未实现 IDbAsyncEnumerable。只有实现 IDbAsyncEnumerable 的源才能用于实体框架异步操作。更多详情请见http://go.microsoft.com/fwlink/?LinkId=287068

为了使用异步方法,我们需要创建一个内存中的 DbAsyncQueryProvider 来处理异步查询。虽然可以使用 Moq 设置查询提供程序,但在代码中创建测试双重实现要容易得多。该实现的代码如下:

等等……

【讨论】:

  • 我确实添加了给定的类,但我不知道如何将它与我的测试联系起来。我目前不使用最小起订量。我会将我所有的代码添加到问题中。 @Hans Passant
【解决方案3】:

我将示例测试类从 here 重命名以删除单词 Test,因为它们在测试之外很有用:

  • DbAsyncEnumerable
  • DbAsyncEnumerator&lt;T&gt;
  • DbAsyncQueryProvider&lt;TEntity&gt;

然后我在下面添加了扩展类,所以你现在可以做...

var data = new List<Blog> 
{ 
    new Blog { Name = "BBB" }, 
    new Blog { Name = "ZZZ" }, 
    new Blog { Name = "AAA" }, 
}.AsAsyncQueryable();   // <<== new extension method

这不仅在单元测试中很有用,而且当您想要实现返回异步数据库查询或内存数据的IQueryable&lt;T&gt; 接口时也很有用,您随后可以安全地调用query.ToAsyncArray()

public static class AsyncQueryableExtensions
{
    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }
}

【讨论】:

  • 帮了我大忙; EF 6、MSTest 和 NSubstitute - 测试一些称为 FirstOrDefaultAsync() 的代码
【解决方案4】:

对于使用上述来自 Microsoft 的样板代码的人来说,这里是一个快速帮助类,可以将您的模拟数据转换为异步结果。只需添加到 MS 代码的底部,然后调用类似

var fakeDateAsMockAsyncQueryResult = new MockAsyncData<SomeType>().MockAsyncQueryResult(fakeDataList.AsQueryable());

.......

internal class MockAsyncData<T> where T : class
{ 
    public Mock<DbSet<T>> MockAsyncQueryResult(IQueryable<T> data)
    {
        var mockSet = new Mock<DbSet<T>>();

        mockSet.As<IDbAsyncEnumerable<T>>()
            .Setup(m => m.GetAsyncEnumerator())
            .Returns(new TestDbAsyncEnumerator<T>(data.GetEnumerator()));

        mockSet.As<IQueryable<T>>()
            .Setup(m => m.Provider)
            .Returns(new TestDbAsyncQueryProvider<T>(data.Provider));

        mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        return mockSet;
    }
}

它与 MS 示例中的代码相同,但通用且可在许多不同的单元测试中重用。

【讨论】:

  • 什么是TestDbAsyncEnumerator和TestDbAsyncQueryProvider?
  • 我遇到了与 User441521 相同的问题。 TestDbAsyncEnumerator 和 TestDbAsyncQueryProvider 都未定义。
  • @PaulGorbas 和其他想知道的人。 Microsoft 指南msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx 中提供了缺少的类 TestDbAsyncEnumeratorTestDbAsyncQueryProvider。您需要将代码复制到您自己的项目中。
【解决方案5】:

解决我的 IDbAsyncEnumerable 问题:

  1. 将我的项目目标从 .NetFramework 4.0 更改为 .NetFramework 4.5

  2. 重新安装 EntityFramework 6.1.3 Nuget 包

  3. 此时,我的 Visual Studio 的 IDE Show Potencial Fixes 顾问允许我引用 System.Data.Entity.Infrastructure 命名空间

使用System.Data.Entity.Infrastructure

【讨论】:

  • 这个怎么用?
  • 嗨@tofutim。抱歉反应迟了。你还在面对这个问题吗?
【解决方案6】:

DbSet 可能隐式实现了IDbSet,因此这些方法不适用于派生类中的interface mapping

不要从IDbSet&lt;TEntity&gt;派生。

You cannot call the explicitly implemented interface members of IDbSet from a re-implementation of that interface.

【讨论】:

  • 我修复了这个错误,但现在我又回到了同一个错误 xD 我将使用我所做的更改来编辑我的帖子。
  • btw 如您所见,我删除了 IDbSet 实现。
【解决方案7】:

没有直接关系,但可能对其他人有所帮助。如果您使用的是 DelegateCompiler,请确保您在 EF 包 (source) 中使用的是 DecompileAsync 而不是 Decompile

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多