gpt4 book ai didi

c# - EntityFrameworkCore 中的 IDbAsyncQueryProvider

转载 作者:太空狗 更新时间:2023-10-29 18:17:34 31 4
gpt4 key购买 nike

我正在使用 XUNIT 在点网核心应用程序中进行测试。

我需要测试一项服务,该服务在我的数据上下文中对 DbSet 进行内部异步查询。

I've seen here异步模拟 DbSet 是可能的。

我遇到的问题是 IDbAsyncQueryProvider 在我使用的 EntityframeworkCore 中似乎不可用。

我这里有错吗?有其他人让这个工作吗?

(漫长的一天,希望我只是遗漏了一些简单的东西)

编辑

在 GitHub 上询问后,我找到了这个类: https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Query/Internal/IAsyncQueryProvider.cs

这是我到目前为止在尝试实现它时所做的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Query.Internal;

namespace EFCoreTestQueryProvider
{
internal class TestAsyncQueryProvider<TEntity>: IAsyncQueryProvider
{
private readonly IQueryProvider _inner;

internal TestAsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}

IQueryable CreateQuery(Expression expression)
{
return new TestDbAsyncEnumerable<TEntity>(expression);
}

IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestDbAsyncEnumerable<TElement>(expression);
}

object Execute(Expression expression)
{
return _inner.Execute(expression);
}

TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}

IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
return Task.FromResult(Execute<TResult>(expression)).ToAsyncEnumerable();
}

Task<TResult> IAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}

internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, System.Collections.Generic.IAsyncEnumerable<T>, IQueryable<T>
{
public TestDbAsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }

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

public IAsyncEnumerator<T> GetAsyncEnumerator()
{
return new TestDbAsyncEnumerable<T>(this.AsEnumerable()).ToAsyncEnumerable();
}

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

IAsyncEnumerator<T> IAsyncEnumerable<T>.GetEnumerator()
{
throw new NotImplementedException();
}

IQueryProvider IQueryable.Provider
{
get { return new TestAsyncQueryProvider<T>(this); }
}
}
}

我现在尝试实现它并遇到了更多问题,特别是围绕这两种方法:

public IAsyncEnumerator<T> GetAsyncEnumerator()
{
return new TestDbAsyncEnumerable<T>(this.AsEnumerable()).ToAsyncEnumerable();
}

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

我希望有人能指出我做错了什么的正确方向。

最佳答案

我终于让它工作了。他们将 EntityFrameworkCore 中的接口(interface)从 IDbAsyncEnumerable 稍微更改为 IAsyncEnumerable 因此以下代码对我有用:

public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
public AsyncEnumerable(Expression expression)
: base(expression) { }

public IAsyncEnumerator<T> GetEnumerator() =>
new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}

public class AsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> enumerator;

public AsyncEnumerator(IEnumerator<T> enumerator) =>
this.enumerator = enumerator ?? throw new ArgumentNullException();

public T Current => enumerator.Current;

public void Dispose() { }

public Task<bool> MoveNext(CancellationToken cancellationToken) =>
Task.FromResult(enumerator.MoveNext());
}

[Fact]
public async Task TestEFCore()
{
var data =
new List<Entity>()
{
new Entity(),
new Entity(),
new Entity()
}.AsQueryable();

var mockDbSet = new Mock<DbSet<Entity>>();

mockDbSet.As<IAsyncEnumerable<Entity>>()
.Setup(d => d.GetEnumerator())
.Returns(new AsyncEnumerator<Entity>(data.GetEnumerator()));

mockDbSet.As<IQueryable<Entity>>().Setup(m => m.Provider).Returns(data.Provider);
mockDbSet.As<IQueryable<Entity>>().Setup(m => m.Expression).Returns(data.Expression);
mockDbSet.As<IQueryable<Entity>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockDbSet.As<IQueryable<Entity>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

var mockCtx = new Mock<SomeDbContext>();
mockCtx.SetupGet(c => c.Entities).Returns(mockDbSet.Object);

var entities = await mockCtx.Object.Entities.ToListAsync();

Assert.NotNull(entities);
Assert.Equal(3, entities.Count());
}

您甚至可以进一步清理 AsyncEnumerableAsyncEnumerator 的那些测试实现。我没有尝试,只是让它起作用了。

请记住,DbContext 上的 DbSet 需要标记为 virtual,否则您需要在 上实现一些接口(interface)包装器>DbContext 以使其正常工作。

关于c# - EntityFrameworkCore 中的 IDbAsyncQueryProvider,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39719258/

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