我正在使用EF Core 3.1.1(dotnet core 3.1.1)。我想退回大量的Car实体。不幸的是,我收到以下错误消息:
'AsyncEnumerableReader' reached the configured maximum size of the buffer when enumerating a value of type 'Microsoft.EntityFrameworkCore.Internal.InternalDbSet`...
我知道关于相同错误还有另一个回答的问题。但是我没有做明确的异步操作。
[HttpGet]
[ProducesResponseType(200, Type = typeof(Car[]))]
public IActionResult Index()
{
return Ok(_carsDataModelContext.Cars.AsEnumerable());
}
_carDataModelContext.Car只是一个简单的实体,将一对一映射到数据库中的表。 public virtual DbSet<Car> Cars { get; set; }
最初,我返回Ok(_carsDataModelContext.Cars.AsQueryable())
是因为我们需要支持OData。但是要确保不是OData搞砸了,我试图返回AsEnumerable,然后从方法中删除“ [EnableQuery]”属性。但这仍然以相同的错误结尾。
解决此问题的唯一方法是,如果我返回Ok(_carsDataModelContext.Cars.ToList())
参考方案
所有Ef Core IQueryable<T>
实现(DbSet<T>
,EntityQueryable<T>
)也实现标准的IAsyncEnumerable<T>
接口(从.NET Core 3使用时),因此AsEnumerable()
,AsQueryable()
和AsAsyncEnumerable()
只需返回相同的接口实例强制转换为相应的接口。
您可以使用以下代码段轻松地进行验证:
var queryable = _carsDataModelContext.Cars.AsQueryable();
var enumerable = queryable.AsEnumerable();
var asyncEnumerable = queryable.AsAsyncEnumerable();
Debug.Assert(queryable == enumerable && queryable == asyncEnumerable);
因此,即使您没有显式返回IAsyncEnumerable<T>
,底层对象也会实现它,并且可以对其进行查询。知道Asp.Net Core是自然的异步框架,我们可以放心地假设它检查对象是否实现了新的标准IAsyncEnumerable<T>
,并在幕后使用它代替了IEnumerable<T>
。
当然,当您使用ToList()
时,返回的List<T>
类不会实现IAsyncEnumerable<T>
,因此唯一的选择是使用IEnumerable<T>
。
这应该解释3.1行为。请注意,在3.0之前,没有标准的IAsyncEnumerable<T>
接口。 EF Core正在实现并返回其自己的异步接口,但是.Net Core基础结构并未意识到这一点,因此无法代表您使用它。
不使用ToList()
/ ToArray()
和类似方法而强制执行先前行为的唯一方法是隐藏基础源(因此IAsyncEnumerable<T>
)。
对于IEnumerable<T>
,这很容易。您需要做的就是创建使用C#迭代器的自定义扩展方法,例如:
public static partial class Extensions
{
public static IEnumerable<T> ToEnumerable<T>(this IEnumerable<T> source)
{
foreach (var item in source)
yield return item;
}
}
然后使用
return Ok(_carsDataModelContext.Cars.ToEnumerable());
如果要返回IQueryable<T>
,事情会变得更加艰难。创建自定义的IQueryable<T>
包装器是不够的,您必须创建自定义的IQueryProvider
包装器,以确保在返回的包装后的IQueryable<T>
上进行撰写将继续返回包装器,直到请求最终的IEnumerator<T>
(或IEnumerator
),并且返回的底层异步可枚举被上述方法隐藏。
这是上面的简化实现:
public static partial class Extensions
{
public static IQueryable<T> ToQueryable<T>(this IQueryable<T> source)
=> new Queryable<T>(new QueryProvider(source.Provider), source.Expression);
class Queryable<T> : IQueryable<T>
{
internal Queryable(IQueryProvider provider, Expression expression)
{
Provider = provider;
Expression = expression;
}
public Type ElementType => typeof(T);
public Expression Expression { get; }
public IQueryProvider Provider { get; }
public IEnumerator<T> GetEnumerator() => Provider.Execute<IEnumerable<T>>(Expression)
.ToEnumerable().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class QueryProvider : IQueryProvider
{
private readonly IQueryProvider source;
internal QueryProvider(IQueryProvider source) => this.source = source;
public IQueryable CreateQuery(Expression expression)
{
var query = source.CreateQuery(expression);
return (IQueryable)Activator.CreateInstance(
typeof(Queryable<>).MakeGenericType(query.ElementType),
this, query.Expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
=> new Queryable<TElement>(this, expression);
public object Execute(Expression expression) => source.Execute(expression);
public TResult Execute<TResult>(Expression expression) => source.Execute<TResult>(expression);
}
}
查询提供程序的实现并不完全正确,因为它假设只有自定义Queryable<T>
会调用Execute
方法来创建IEnumerable<T>
,而外部调用仅用于直接方法,例如Count
,FirstOrDefault
, Max
等,但它适用于这种情况。
此实现的另一个缺点是,所有EF Core特定的Queryable
扩展都无法使用,如果OData $expand
依赖于Include
/ ThenInclude
之类的方法,则可能是一个问题/问题的解决者。但是要解决该问题,需要更复杂的实现,并深入EF Core内部。
话虽这么说,用法当然是:
return Ok(_carsDataModelContext.Cars.ToQueryable());
合并List <T>和List <Optional <T >> - java鉴于: List<Integer> integers = new ArrayList<>(Arrays.asList( 10, 12 )); List<Optional<Integer>> optionalIntegers = Arrays.asList( Optional.of(5), Optional.em…
无法从ArrayList <String>转换为List <Comparable> - java当我写下面的代码时,编译器说 无法从ArrayList<String>转换为List<Comparable>private List<Comparable> get(){ return new ArrayList<String>(); } 但是当我用通配符编写返回类型时,代码会编译。private List&l…
OpenShift构建错误:无法在多模块Maven Spring启动项目的父模块中导入子模块类 - java我有一个使用spring的多模块Maven项目。通用模块类用作业务模块项目中的直接导入。我可以在本地PC上编译并成功运行它们。当我在OpenShift中部署相同的模块时,出现错误,无法在业务模块中导入通用模块类。项目结构可以总结如下:项目根 通用模块 src pom.xml 业务模块 src pom.xml pom.xml父POM:<?xml vers…
List <Dog>是List <Animal>的子类吗?为什么Java泛型不是隐式多态的? - java我对Java泛型如何处理继承/多态感到困惑。假设以下层次结构-动物(父母)狗-猫(儿童)因此,假设我有一个方法doSomething(List<Animal> animals)。根据继承和多态性的所有规则,我假设List<Dog>是List<Animal>,而List<Cat>是List<Animal&g…
将谓词<T>转换为Func <T,bool> - c#我有一个包含成员Predicate的类,希望在Linq表达式中使用该类:using System.Linq; class MyClass { public bool DoAllHaveSomeProperty() { return m_instrumentList.All(m_filterExpression); } private IEnumerable&…