Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# AutoMapper无法将TestDbAsyncEnumerable强制转换为IQueryable_C#_Entity Framework_Automapper - Fatal编程技术网

C# AutoMapper无法将TestDbAsyncEnumerable强制转换为IQueryable

C# AutoMapper无法将TestDbAsyncEnumerable强制转换为IQueryable,c#,entity-framework,automapper,C#,Entity Framework,Automapper,我已经从中实现了TestDbAsync fakes,我希望能够在调用Async EF方法(ToListAsync、CountAsync等)之前使用AutoMapper投影到不同的类型 我在ProjectionExpression.To中遇到强制转换异常 引发异常的示例代码 _userRepository.GetAll().OrderBy(x => x.Id).ProjectTo<User>.ToListAsync(); 现在为了解决这个问题,我必须在调用Async EF扩展之

我已经从中实现了TestDbAsync fakes,我希望能够在调用Async EF方法(ToListAsync、CountAsync等)之前使用AutoMapper投影到不同的类型

我在ProjectionExpression.To中遇到强制转换异常

引发异常的示例代码

_userRepository.GetAll().OrderBy(x => x.Id).ProjectTo<User>.ToListAsync();
现在为了解决这个问题,我必须在调用Async EF扩展之后进行ProjectTo。有没有办法让ProjectTo在EF扩展之前调用

参考代码:

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;
    }
公共类TestDbAsyncEnumerable:EnumerableQuery、IDbAsyncEnumerable、IQueryable { 公共TestDbAsyncEnumerable(IEnumerable enumerable) :基本(可枚举) { } 公共TestDbAsyncEnumerable(表达式) :base(表达式) { } 公共IDbAsyncEnumerator GetAsyncEnumerator() { 返回新的TestDbAsyncEnumerator(this.AsEnumerable().GetEnumerator()); } IDBSyncEnumerator IDBSyncEnumeratable.GetAsyncEnumerator() { 返回GetAsyncEnumerator(); } IQueryProvider IQueryable.Provider=>新的TestDbAsyncQueryProvider(此); } 公共静态模拟到SyncDBSetMock(此IEnumerable源) T:在哪里上课 { var data=source.AsQueryable(); var mockSet=new Mock(); mockSet.As() .Setup(m=>m.GetAsyncEnumerator()) .Returns(新的TestDbAsyncEnumerator(data.GetEnumerator()); mockSet.As() .Setup(m=>m.Provider) .Returns(新的TestDbAsyncQueryProvider(data.Provider)); mockSet.As().Setup(m=>m.Expression).Returns(data.Expression); mockSet.As().Setup(m=>m.ElementType).Returns(data.ElementType); mockSet.As().Setup(m=>m.GetEnumerator()).Returns(data.GetEnumerator()); 返回模拟集; }
从Automapper 6.0.2升级到6.1.1后,我在测试中遇到了同样的错误。降级回6.0.2修复了该问题


不确定这是Automapper的回归还是突破性变化。除了查看更改日志和github问题,我没有时间进一步研究它。没有跳出任何内容。

编辑您的
TestDbAsyncQueryProvider.CreateQuery()
,以便它返回由
项目传递到的正确类型的表达式

这是我的示例实现

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);
}
public IQueryable CreateQuery(表达式)
{
开关(表达式)
{
case MethodCallExpression m:
{
var resultType=m.Method.ReturnType;//它应该是可查询的
var tElement=resultType.GetGenericArguments()[0];
var queryType=typeof(TestDbAsyncEnumerable);
return(IQueryable)Activator.CreateInstance(queryType,expression);
}
}
返回新的TestDbAsyncEnumerable(表达式);
}

我还编写了单元测试。它起作用了


我遇到了同样的问题,除了公认的答案之外,您可能也会像我一样拥有CreateQuery的通用版本-我也这样修复了这个问题:

public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
    var queryType = typeof(TestDbAsyncEnumerable<>).MakeGenericType(typeof(TElement));
    return (IQueryable<TElement>)Activator.CreateInstance(queryType, expression);
}
public IQueryable CreateQuery(表达式)
{
var queryType=typeof(TestDbAsyncEnumerable)。MakeGenericType(typeof(TElement));
return(IQueryable)Activator.CreateInstance(queryType,expression);
}

该类型由TElement提供,因此它在通用版本上的实现更简单。

通过结合使用上述两个答案,帮助我在单元测试中使用.ProjectTo

在TestDbAsyncQueryProvider实现中,我替换了以下两种方法:

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

public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
    var queryType = typeof(TestDbAsyncEnumerable<>).MakeGenericType(typeof(TElement));
    return (IQueryable<TElement>)Activator.CreateInstance(queryType, expression);
}

public IQueryable CreateQuery(表达式)
{
开关(表达式)
{
case MethodCallExpression m:
{
var resultType=m.Method.ReturnType;//它应该是可查询的
var tElement=resultType.GetGenericArguments()[0];
var queryType=typeof(TestDbAsyncEnumerable);
return(IQueryable)Activator.CreateInstance(queryType,expression);
}
}
返回新的TestDbAsyncEnumerable(表达式);
}
公共IQueryable CreateQuery(表达式)
{
var queryType=typeof(TestDbAsyncEnumerable)。MakeGenericType(typeof(TElement));
return(IQueryable)Activator.CreateInstance(queryType,expression);
}

它可以与今天最新的EF6配合使用。

如果实体上有人有其他对象,ProjectTo将崩溃或抛出带有空引用对象的异常

解决方案是确保您的实体的所有对象都用default()或其他东西初始化

在此处的最后一条评论/答案中找到答案->


另外,感谢IAsyncQueryProvider的实现:)

没有考虑降级。我们最终将EF调用抽象到一个接口后面进行测试。如果有人对贡献感兴趣,我们也可以在AM内部解决。很高兴看到有人跟踪根本原因。我喜欢你的产品!谢谢拯救了我的一天:P
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);
}

public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
    var queryType = typeof(TestDbAsyncEnumerable<>).MakeGenericType(typeof(TElement));
    return (IQueryable<TElement>)Activator.CreateInstance(queryType, expression);
}