EF Core 3.1引发包含的异常

问题描述 投票:1回答:1

我最近将项目代码更新到了.NET Core 3.1和EF Core 3.1,现在我的大多数linq查询都是EX,

public override ICollection<ContactDetailModel> GetAll(ICollection<int> ids)
{
            return _context
                .Set<TEntity>()
                .IgnoreDeletedEntities()                
                .Where(x => ids.Distinct().Contains(x.ContactId))                
                .Select(EntityToDTOMapper)
                .ToList();
}

此代码在使用Contains时引发错误,我在其他一些文章中看到此问题已作为bug修复,但失败了。

我得到的错误是“无法翻译。要么以可以翻译的形式重写查询,要么通过插入对AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync的调用来显式切换到客户端评估()。“

System.InvalidOperationException
  HResult=0x80131509
  Message=The LINQ expression 'DbSet<SupplierContactDetails>
    .Where(s => !(s.DeletedOn.HasValue) && !(s.DeletedBy.HasValue))
    .Where(s => __Distinct_0
        .Contains(s.ContactId))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|8_0(ShapedQueryExpression translated, <>c__DisplayClass8_0& )
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at BlueTag.DAL.Repositories.ContactRepository`1.GetAll(ICollection`1 ids) in D:\Projects\BlueTag Version 2\.net-core-server\DAL\Repositories\ContactRepository.cs:line 95
   at BlueTag.DAL.Repositories.SupplierRepository.ToDomain(IEnumerable`1 supplier) in D:\Projects\BlueTag Version 2\.net-core-server\DAL\Repositories\SupplierRepository.cs:line 216
   at BlueTag.DAL.Repositories.SupplierRepository.GetFilteredSuppliers(RequestPagingOptionsModel`1 options) in D:\Projects\BlueTag Version 2\.net-core-server\DAL\Repositories\SupplierRepository.cs:line 129
   at BlueTag.Supplier.Services.SupplierService.GetFilteredSupplierDetails(RequestPagingOptionsModel`1 options) in D:\Projects\BlueTag Version 2\.net-core-server\Supplier\Serrvices\SupplierService.cs:line 49
   at BlueTag.Supplier.Controllers.SupplierController.GetFilteredSuppliers(RequestPagingOptionsModel`1 options) in D:\Projects\BlueTag Version 2\.net-core-server\Supplier\Controllers\SupplierController.cs:line 54
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

c# asp.net-core linq-to-sql asp.net-core-webapi ef-core-3.0
1个回答
0
投票

Entity Framework无法转换每个查询,因此,有时它必须加载所有数据并在内存中执行LINQ表达式,这被称为客户端评估,这是不希望的,因为它占用更多的资源并且需要更长的时间。对于您的特定问题,有2个解决方案,错误消息中都列出了这两种解决方案。

1)重写您的LINQ查询,以包括对客户端评估的显式调用与隐式调用

2)重写您的LINQ查询,不需要客户端评估

您可以像这样做1号:

public override ICollection<ContactDetailModel> GetAll(ICollection<int> ids)
{
    return _context
        .Set<TEntity>()
        .IgnoreDeletedEntities()
        .ToList()                
        .Where(x => ids.Distinct().Contains(x.ContactId))                
        .Select(EntityToDTOMapper)
        .ToList();
}

[请注意在ToList之后显式调用IgnoreDeletedEntities,这需要显式切换到客户端评估,以便您的Where语句将正确执行且不会引发任何错误。这是因为x => ids.Distinct().Contains(x.ContactId)无法通过您的EF版本转换为SQL(或任何其他形式)。

数字2可以这样解决:

public override ICollection<ContactDetailModel> GetAll(ICollection<int> ids)
{
    ids = ids.Distinct();
    return _context
        .Set<TEntity>()
        .IgnoreDeletedEntities()
        .Where(x => ids.Contains(x.ContactId))
        .Select(EntityToDTOMapper)
        .ToList();
}

请注意我是如何将ids.Distinct()的使用从Where移到顶部的,因为那是EF无法翻译的部分

© www.soinside.com 2019 - 2024. All rights reserved.