Я пытаюсь создать общий способ получения данных через EF Core 3.1 с одинаковой фильтрацией разных дочерних элементов. Для этого я пытаюсь извлечь искомое выражение внутри Any(...).
public Expression<Func<PraeparatUpdateEntity, bool>> IsToApprovePackungUpdates_Working()
{
return entity => entity.PackungUpdates.Any(e => !e.IsImported
&& e.UpdateState != EntityUpdateState.Accepted
&& e.UpdateType != EntityUpdateType.Unchanged);
}
public Expression<Func<PraeparatUpdateEntity, bool>> IsToApprovePackungUpdates_NotWorking()
{
var func = new Func<PackungUpdateEntity, bool>(e => !e.IsImported
&& e.UpdateState != EntityUpdateState.Accepted
&& e.UpdateType != EntityUpdateType.Unchanged);
return entity => entity.PackungUpdates.Any(func);
}
public new async Task<ICollection<PraeparatUpdateEntity>> GetToApproveAsync(bool trackChanges = false)
{
var query = Set.Include(praeparatUpdateEntity => praeparatUpdateEntity.PackungUpdates)
.Where(IsToApprovePackungUpdates_NotWorking());
if (!trackChanges)
{
query = query.AsNoTracking();
}
return await query.ToListAsync();
}
Первая версия работает. Второй терпит неудачу с сообщением об ошибке:
System.ArgumentException : Expression of type 'System.Func`2[MyProject.Data.Common.Entities.Update.PackungUpdateEntity,System.Boolean]' cannot be used for parameter of type 'System.Linq.Expressions.Expression`1[System.Func`2[MyProject.Data.Common.Entities.Update.PackungUpdateEntity,System.Boolean]]' of method 'Boolean Any[PackungUpdateEntity](System.Linq.IQueryable`1[MyProject.Data.Common.Entities.Update.PackungUpdateEntity], System.Linq.Expressions.Expression`1[System.Func`2[MyProject.Data.Common.Entities.Update.PackungUpdateEntity,System.Boolean]])' (Parameter 'arg1')
at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at Microsoft.EntityFrameworkCore.Query.Internal.EnumerableToQueryableMethodConvertingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)
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__DisplayClass12_0`1.<ExecuteAsync>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.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at MyProject.Data.Repositories.PraeparatUpdateRepository.GetToApproveAsync(Boolean trackChanges) in C:\git\MyProject\Source\MyProject.Data\Repositories\PraeparatUpdateRepository.cs:line 156
at MyProject.Data.Tests.Integration.RepositoryNavigationPropertyLoadingTests.GetAllPraeparatUpdates_WhereToApprove_WithNavigationProperties_OK_Test() in C:\git\MyProject\Source\MyProject.Data.Tests.Integration\RepositoryNavigationPropertyLoadingTests.cs:line 328
--- End of stack trace from previous location where exception was thrown ---
******** ОБНОВИТЬ ********
Если я добавлю AsQueryable() к своим дочерним элементам базы данных IEnumerable, я могу добавить свои выражения следующим образом:
var query = Set.Include(praeparatUpdateEntity => praeparatUpdateEntity.PackungUpdates)
.Include(praeparatUpdateEntity => praeparatUpdateEntity.SequenzUpdates)
.ThenInclude(sequenzUpdateEntity => sequenzUpdateEntity.ApplikationsartUpdates)
.Include(praeparatUpdateEntity => praeparatUpdateEntity.SequenzUpdates)
.ThenInclude(sequenzUpdateEntity => sequenzUpdateEntity.DeklarationUpdates)
.Where(IsToApprove<PraeparatUpdateEntity>()
.OrElse(entity => entity.PackungUpdates.AsQueryable().Any(IsToApprove<PackungUpdateEntity>()))
.OrElse(entity => entity.SequenzUpdates.AsQueryable().Any(IsToApprove<SequenzUpdateEntity>()))
.OrElse(entity => entity.SequenzUpdates.SelectMany(sequenzUpdateEntity => sequenzUpdateEntity.ApplikationsartUpdates).AsQueryable()
.Any(IsToApprove<ApplikationsartUpdateEntity>()))
.OrElse(entity => entity.SequenzUpdates.SelectMany(sequenzUpdateEntity => sequenzUpdateEntity.DeklarationUpdates).AsQueryable()
.Any(IsToApprove<DeklarationUpdateEntity>())));
и мое общее выражение:
public Expression<Func<T, bool>> IsToApprove<T>() where T : class, IUpdateEntity
{
return entity => !entity.IsImported && entity.UpdateState != EntityUpdateState.Accepted
&& entity.UpdateType != EntityUpdateType.Unchanged;
}
который, кажется, на данный момент работает... Идут испытания
If I add AsQueryable() to my IEnumerable database children
они ужеIQueryable
, а неIEnumerable
.DbSet<T>
реализуетIQueryable<T>
, поэтому с ним можно использовать LINQ. Проблема в том, что ваше универсальное выражение на самом деле представляет собой вызов конкретной функции с использованиемAny
, который нельзя преобразовать в SQL. На самом деле работает это выражение для конкретной сущности. Что ты пытаешься сделать? Что бы это ни было, оно не требует таких сложных выражений - person Panagiotis Kanavos   schedule 31.08.2020parent LEFT JOIN (select ... from child where child.IsApproved =10 c on c.ParentID=parent.ID
- person Panagiotis Kanavos   schedule 31.08.2020