首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何模拟实体框架6异步投影查询

如何模拟实体框架6异步投影查询
EN

Stack Overflow用户
提问于 2014-03-31 19:15:38
回答 1查看 3.2K关注 0票数 7

通过利用MSDN文章,我能够创建许多成功通过测试的方法。

下面是我的测试代码,它将NSubstitute用于模拟:

代码语言:javascript
复制
var dummyQueryable = locations.AsQueryable();

var mock = Substitute.For<DbSet<Location>, IDbAsyncEnumerable<Location>, IQueryable<Location>>();
((IDbAsyncEnumerable<Location>)mock).GetAsyncEnumerator().Returns(new TestDbAsyncEnumerator<Location>(dummyQueryable.GetEnumerator()));
((IQueryable<Location>)mock).Provider.Returns(new TestDbAsyncQueryProvider<Location>(dummyQueryable.Provider));
((IQueryable<Location>)mock).Expression.Returns(dummyQueryable.Expression);
((IQueryable<Location>)mock).ElementType.Returns(dummyQueryable.ElementType);
((IQueryable<Location>)mock).GetEnumerator().Returns(dummyQueryable.GetEnumerator());
sut.DataContext.Locations = mock;

var result = await sut.Index();

result.Should().BeView();

sut.Index()做的不多,但它提供了以下查询:

代码语言:javascript
复制
await DataContext.Locations
    .GroupBy(l => l.Area)
    .ToListAsync());

在我向查询中添加一个投影之前,这是很好的:

代码语言:javascript
复制
await DataContext.Locations
    .GroupBy(l => l.Area)
    .Select(l => new LocationsIndexVM{ Area = l.Key }) // added projection
    .ToListAsync());

这导致了这一例外:

代码语言:javascript
复制
System.InvalidOperationException
The source IQueryable doesn't implement IDbAsyncEnumerable<LocationsIndexVM>. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.
   at System.Data.Entity.QueryableExtensions.AsDbAsyncEnumerable(IQueryable`1 source)
   at System.Data.Entity.QueryableExtensions.ToListAsync(IQueryable`1 source)
   at Example.Web.Controllers.HomeController.<Index>d__0.MoveNext() in HomeController.cs: line 25
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Example.Test.Web.Controllers.HomeControllerShould.<TempTest>d__4.MoveNext() in HomeControllerShould.cs: line 71

UPDATE:我有再现这个问题的上传了一个简单的小解决方案

有人能提供一个例子,说明单元测试既包含async又包含.Select()投影的查询所需的内容吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-03 03:06:20

所以我做了一些调查,问题与TestDbAsyncEnumerable<T>公开IQueryProvider的方式有关。我对推理的最好猜测是下面,下面是解决办法。

TestDbAsyncEnumerable<T>继承EnumerableQuery<T>,后者又继承IQueryable<T>,并显式实现此接口的Provider属性:

代码语言:javascript
复制
IQueryProvider IQueryable.Provider { get ... }

考虑到它是显式实现的,我假设LINQ内部元素在尝试获取Provider之前显式地强制转换了一个类型

代码语言:javascript
复制
((IQueryable<T>)source).Provider.CreateQuery(...);

我手头上没有源代码(也不会费心寻找源),但我认为类型绑定规则对于显式实现是不同的;本质上,Provider属性并不被认为是IQueryable<T>.Provider的实现,因为在链的更远的地方存在显式的IQueryable<T>.Provider属性,因此永远不会返回您的TestDbAsyncQueryProvider<T>

解决这个问题的方法是让TestDbAsyncEnumerable<T>也继承IQueryable<T>并显式实现Provider属性,如下所示(从您链接的MSDN文章中调整):

代码语言:javascript
复制
public class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
    public TestDbAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable)
    { }

    public TestDbAsyncEnumerable(Expression expression) : base(expression)
    { }

    public IDbAsyncEnumerator<T> GetAsyncEnumerator()
    {
        return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
    }

    IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
    {
        return GetAsyncEnumerator();
    }

    IQueryProvider IQueryable.Provider
    {
        get { return new TestDbAsyncQueryProvider<T>(this); }
    }
}
票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22770206

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档