C# “解决”;InvalidOperationException:无法翻译LINQ表达式[…];以及保持ToListSync()
在EF Core 3.x中,无法翻译的LINQ查询不再在客户端上计算。据我所知,这意味着它无法处理无法直接转换为SQL的代码C# “解决”;InvalidOperationException:无法翻译LINQ表达式[…];以及保持ToListSync(),c#,asp.net,linq,asp.net-core,ef-core-3.0,C#,Asp.net,Linq,Asp.net Core,Ef Core 3.0,在EF Core 3.x中,无法翻译的LINQ查询不再在客户端上计算。据我所知,这意味着它无法处理无法直接转换为SQL的代码 在我的例子中,我想使用foreach(type.GetProperties()中的PropertyInfo)来计算类的每个组件 private static bool stringInMovement(Movement m, string toTest) { foreach(PropertyInfo component in typeof(Movement).G
在我的例子中,我想使用foreach(type.GetProperties()中的PropertyInfo)来计算类的每个组件
private static bool stringInMovement(Movement m, string toTest)
{
foreach(PropertyInfo component in typeof(Movement).GetProperties())
{
try {
if (component.GetValue(m).ToString().ToLower().Contains(toTest.ToLower()))
return true;
}
catch { }
}
return false;
}
然后在where语句中使用:
movements = movements.Where(m=> stringInMovement(m, SearchString));
我希望将结果保持为IQueryable,因为它所在的函数之后是一个异步任务,最后一行是
Movements = await movements.AsNoTracking().ToListAsync();
我希望将all函数保持为异步函数,并且不希望必须使用10x m.Component.Contains(searchstring)编写where语句。顺便说一下,它是用来搜索数据库中的特定元素的
谢谢你的帮助
尝试搜索某些内容时出现的错误:
Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslationExpressionVisitor.g_uCheckTranslated | 8_0(ShapedQueryExpression translated,参考c_uDisplayClass8_0)
Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslationExpressionVisitor.VisitMethodCall(MethodCallExpression MethodCallExpression)
Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslationExpressionVisitor.VisitMethodCallExpression(MethodCallExpression MethodCallExpression)
System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor)
System.Linq.Expressions.ExpressionVisitor.Visit(表达式节点)
Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor(表达式查询)
Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery(表达式查询,bool异步)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore(IDatabase数据库、表达式查询、IModel模型、bool异步)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+c\u显示类12\u 0.b\u 0()
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOradQueryCore(对象缓存键,Func编译器)
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOradQuery(对象缓存键,Func编译器)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync(表达式查询,取消令牌取消令牌)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync(表达式表达式,CancellationToken CancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable.GetAsyncEnumerator(CancellationToken CancellationToken)
System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable.GetAsyncEnumerator()
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListSync(IQueryable源,CancellationToken CancellationToken)
Index.cshtml.cs中的Intuo.IndexModel.OnGetAsync()
+
移动=等待移动。AsNoTracking().toListSync();
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+NonGenericTaskHandlerMethod.Execute(对象接收器,对象[]参数)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(ref状态Next,ref作用域,ref对象状态,ref bool已完成)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g_|24_0(ResourceInvoker invoker,Task lastTask,State next,Scope Scope,object State,bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed上下文)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref状态Next、ref作用域、ref对象状态、ref bool已完成)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g|u waiting | 17|0(ResourceInvoker invoker,Task Task,IDisposable作用域)
Microsoft.AspNetCore.Routing.EndpointMiddleware.g_uwaitRequestTask | 6_0(端点端点、任务请求任务、ILogger记录器)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext上下文)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext上下文)
您想要的是动态生成一个
表达式
,以便在where子句中使用
公共静态表达式包含字符串(字符串值)
{
var constValue=表达式常数(值);
var参数=表达式参数(类型为(T),“p”);
返回表达式.Lambda(
typeof(T).GetProperties()
.Where(p=>p.PropertyType==typeof(字符串))
.选择(p=>(表达式)Expression.Call(
表达式.Property(参数p),
“包含”,
新类型[]{typeof(string)},
常量值)
.Aggregate((a,c)=>Expression.OrElse(a,c)),
参数);
}
移动=移动。其中(包含字符串(搜索字符串));
EF/EF核心无法将任何涉及反射或更复杂逻辑的内容转换为SQL。与此相反,有几种方法可以实现所需的功能—在查询中编写所有道具:
movements = movements
.Where(m => m.Property1.ToString().ToLower().Contains(SearchString.ToString().ToLower() &&
m.Property2.ToString().ToLower().Contains(SearchString.ToString().ToLower() /* ... */ );
或者构建特定的表达式
,该表达式将作为参数传递到。其中
通过自定义或使用方法:
public static Expression<Func<Movement, bool>> CompareToStr(string searchString)
{
Expression res = null;
var param = Expression.Parameter(typeof(Movement), "x");
foreach (var component in typeof(Movement).GetProperties())
{
// building the expression to get a property
var arg = Expression.Property(param, component.Name);
// now we have `x.Property1` expression
var toStrCall = Expression.Call(
// to what expression we applying the .ToString method
arg,
// link to 'ToString',
// needed to be altered, if it would be used in non-sql runtime as if there are nullable types with `null` values, this would cause NRE at runtime
component.PropertyType.GetMethod(nameof(object.ToString), new Type[] { }));
// now we have `x.Property1.ToString()` (watch out NRE)
var toLowerCall = Expression.Call(
toStrCall,
typeof(string).GetMethod(nameof(string.ToLower), new Type[] { }));
// now we have `x.Property1.ToString().ToLower()`
var containsCall = Expression.Call(
toLowerCall,
typeof(string).GetMethod(nameof(string.Contains), new[] { typeof(string) }),
Expression.Constant(searchString.ToLower())); // since arguments of expression tree should be the expressions
// here we passed the constant string expression, so now we have
// x.Property1.ToString().ToLower().Contains( value of testString.ToLower())
if (res == null)
{
res = containsCall;
}
else
{
res = Expression.Or(res, containsCall);
}
// after several iterations it has
// x.Property1...Contains(testString) || x.Property2...Contains(testString) and so on
}
return Expression.Lambda<Func<Movement, bool>>(res, param);
// and result x => x.Property1... || x.Property2 ...
}
@Matomat
ToString
方法是在object
类中定义的,因此应该可以调用ToStr
public static Expression<Func<Movement, bool>> CompareToStr(string searchString)
{
Expression res = null;
var param = Expression.Parameter(typeof(Movement), "x");
foreach (var component in typeof(Movement).GetProperties())
{
// building the expression to get a property
var arg = Expression.Property(param, component.Name);
// now we have `x.Property1` expression
var toStrCall = Expression.Call(
// to what expression we applying the .ToString method
arg,
// link to 'ToString',
// needed to be altered, if it would be used in non-sql runtime as if there are nullable types with `null` values, this would cause NRE at runtime
component.PropertyType.GetMethod(nameof(object.ToString), new Type[] { }));
// now we have `x.Property1.ToString()` (watch out NRE)
var toLowerCall = Expression.Call(
toStrCall,
typeof(string).GetMethod(nameof(string.ToLower), new Type[] { }));
// now we have `x.Property1.ToString().ToLower()`
var containsCall = Expression.Call(
toLowerCall,
typeof(string).GetMethod(nameof(string.Contains), new[] { typeof(string) }),
Expression.Constant(searchString.ToLower())); // since arguments of expression tree should be the expressions
// here we passed the constant string expression, so now we have
// x.Property1.ToString().ToLower().Contains( value of testString.ToLower())
if (res == null)
{
res = containsCall;
}
else
{
res = Expression.Or(res, containsCall);
}
// after several iterations it has
// x.Property1...Contains(testString) || x.Property2...Contains(testString) and so on
}
return Expression.Lambda<Func<Movement, bool>>(res, param);
// and result x => x.Property1... || x.Property2 ...
}
movements = movements.Where(CompareToStr(SearchString));