c# - AutoMapper 无法将 TestDbAsyncEnumerable 转换为 IQueryable

标签 c# entity-framework automapper

我已经实现了来自 https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx 的 TestDbAsync 伪造并且我希望能够在调用 Async EF 方法(ToListAsync、CountAsync 等)之前使用 AutoMapper 投影到不同的类型。

我在 ProjectionExpression.To 中得到一个转换异常

抛出异常的示例代码。

_userRepository.GetAll().OrderBy(x => x.Id).ProjectTo<User>.ToListAsync();

这在非测试场景中工作正常,但是当我使用 TestDbAsyncEnumerable 模拟 DbSet 时,我得到了

: Unable to cast object of type 'Namespace.TestDbAsyncEnumerable`1[UserEntity]' to type 'System.Linq.IQueryable`1[User]'.

现在为了解决这个问题,我必须在调用 Async EF 扩展后进行 ProjectTo。有没有办法在 EF 扩展之前保持 ProjectTo 调用?

引用代码:

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 => new TestDbAsyncQueryProvider<T>(this);
}

public static Mock<DbSet<T>> ToAsyncDbSetMock<T>(this IEnumerable<T> source)
        where T : class
    {

        var data = source.AsQueryable();

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

最佳答案

编辑您的 TestDbAsyncQueryProvider<>.CreateQuery()以便它返回 ProjectTo<> 传递的表达式的正确类型.

这是我的示例实现。

public IQueryable CreateQuery(Expression expression)
{
    switch (expression)
    {
        case MethodCallExpression m:
            {
                var resultType = m.Method.ReturnType; // it shoud be IQueryable<T>
                var tElement = resultType.GetGenericArguments()[0];
                var queryType = typeof(TestDbAsyncEnumerable<>).MakeGenericType(tElement);
                return (IQueryable)Activator.CreateInstance(queryType, expression);
            }
    }
    return new TestDbAsyncEnumerable<TEntity>(expression);
}

https://gist.github.com/masaedw/95ab972f8181de6bbe48a20ffe9be113

我也写过单元测试。它正在工作。

https://github.com/masaedw/AutoMapper/blob/TestDbAsync/src/IntegrationTests/MockedContextTests.cs

关于c# - AutoMapper 无法将 TestDbAsyncEnumerable 转换为 IQueryable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44807618/

相关文章:

c# - 解决方案的本地构建适用于 .NET 7,但不适用于管道

c# - 如何从下拉列表传递参数

c# - 如何将 .NET Core 项目部署到 Windows Server 2012 R2

.net - Entity Framework 4 在两次执行相同的查询时返回到数据库

c# - 领域模型映射

c# - 自动映射内部服务引用

c# - 在 Visual Studio 中获取类的程序集限定名称

c# - 无法将 Entity Framework 成员更改为 protected

c# - Entity Framework 中可重用的 linq 选择查询

c# - 如何从 EF sql 查询返回匿名类型