gpt4 book ai didi

entity-framework - 如何模拟 Entity Framework 6 异步投影查询

转载 作者:行者123 更新时间:2023-12-04 10:04:09 30 4
gpt4 key购买 nike

通过利用 Testing with async queries section of the Testing with a Mocking Framework article on MSDN ,我已经能够创建许多成功通过的测试。

这是我的测试代码,它使用 NSubstitute对于模拟:

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()没有做太多,但它会进行以下查询:
await DataContext.Locations
.GroupBy(l => l.Area)
.ToListAsync());

在我将投影添加到查询中之前,这可以正常工作:
await DataContext.Locations
.GroupBy(l => l.Area)
.Select(l => new LocationsIndexVM{ Area = l.Key }) // added projection
.ToListAsync());

这导致了这个异常:
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

更新 : 我有 uploaded a small, simple solution重现了这个问题。

任何人都可以提供一个示例,说明单元测试查询所需的内容 async并包含 .Select()投影?

最佳答案

所以我做了一些挖掘,问题与 TestDbAsyncEnumerable<T> 的方式有关。暴露 IQueryProvider .我对推理的最佳猜测如下,以及下面的解决方案。
TestDbAsyncEnumerable<T>继承自 EnumerableQuery<T> ,它又继承自 IQueryable<T> , 并显式实现 Provider该接口(interface)的属性:

IQueryProvider IQueryable.Provider { get ... }

鉴于它是显式实现的,我假设 LINQ 内部在尝试获取 Provider 之前显式转换了一个类型。 :
((IQueryable<T>)source).Provider.CreateQuery(...);

我手头没有资源(也懒得找资源),但我相信类型绑定(bind)规则对于显式实现是不同的;本质上, Provider您的 TestDbAsyncEnumerable<T> 上的属性(property)不被视为 IQueryable<T>.Provider 的实现作为一个明确的存在于链条的更上游,所以你的 TestDbAsyncQueryProvider<T>永远不会返回。

解决此问题的方法是使 TestDbAsyncEnumerable<T>也继承 IQueryable<T>并明确实现 Provider属性,如下(从 MSDN article you linked 调整):
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); }
}
}

关于entity-framework - 如何模拟 Entity Framework 6 异步投影查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22770206/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com