EF Core 3.1 создает исключение для Contains - PullRequest
1 голос
/ 26 февраля 2020

Я недавно обновил код проекта до. 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, Я видел в некоторых других сообщениях, что эти проблемы были исправлены как ошибка, но все же это терпит неудачу.

Ошибка, которую я получаю, "не могла быть переведена. Перепишите запрос в форме, которая может быть переведена, или переключитесь для оценки клиента в явном виде, вставив вызов либо AsEnumerable (), AsAsyncEnumerable (), ToList (), либо ToListAsyn c (). "

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()

1 Ответ

0 голосов
/ 26 февраля 2020

Entity Framework не может перевести каждый запрос, и поэтому ему иногда приходится загружать все данные и выполнять выражение LINQ в памяти, это называется оценкой на стороне клиента и нежелательно, так как требует больше ресурсов и занимает больше времени. , Для вашей конкретной проблемы c есть 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) не может быть переведен в SQL (или что-то еще) вашей версией EF.

Номер 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 не мог перевести

...