如何避免在LINQ表达式中进行动态调用

如何解决如何避免在LINQ表达式中进行动态调用

我想问你如何避免与LINQ表达式中的动态调用相关的错误。

现有错误:

不支持方法'System.Object DynamicInvoke(System.Object [])' 转换为SQL

代码示例(LINQPad):

编辑:

void Main()
{
var entity = new[] 
{     
    new Customers    {  CustomerID = "ALFKI",CompanyName = "Alfreds Futterkiste",ContactName = "Maria Anders"},new Customers    {  CustomerID = "ANATR",CompanyName = "Ana Trujillo Emparedados y helados",ContactName = "Ana Trujillo"},new Customers    {  CustomerID = "2",CompanyName = "Louis Vuiton2",ContactName = "Dom2"}};

    var result = Exists(entity,x => x.CustomerID + " " + x.CompanyName); 
}


IDictionary<string,bool> Exists(IEnumerable<Customers> data,Func<Customers,object> predicate)
{  
   Expression<Func<Customers,object>> expression = x => predicate(x);
   var ids = data.AsQueryable().Select(x=>predicate(x));        
   var existing = Customers.Where(x => ids.Contains(expression)).ToList(); //Error line.

   //I do not want to materialize query after Customers for example Customers.ToList()[...]

   data.ToList().ForEach(x => existing.Any(y=> predicate(y).ToString() == predicate(x).ToString()));
   var dictionary = data.ToDictionary(x => x.CustomerID.ToString(),x => existing.Any(y => predicate(y).ToString() == predicate(x).ToString()));               

   return dictionary; 
}   

编辑: 现有的var应该返回:

enter image description here

但返回null。

解决方法

这是避免重复转换为字符串的方法。您真正想要的是获取数组并将其转换为可以应用于客户对象的表达式,然后使用Expression.OrElse聚合这些表达式,以创建一个单个查询表达式,然后将其应用于数据库。

这并不简单,但这是如何做到的。

您将像这样在最后调用该方法:

var result = Exists(Customers.AsQueryable(),entity,(q) => c => (q.CustomerID == c.CustomerID && q.CompanyName == c.CompanyName)); 

相对于比较中的所有内容,这具有多个优势。首先,数据库可以使用索引优化查询。对于另一个,您可以传递更复杂的表达式,如果需要的话,可以通过简单的字符串比较来进行传递,例如c.CustomerID > q.CustomerID

我已将CustomerQuery类与CustomerClass分开,因为它们是不同的(并固定了您的多元性)。

完成工作的实际方法非常简单。之前的所有方法都用于重写具有不同参数的表达式以创建要创建的OrElse表达式。这些方法通常在您想操纵表达式并了解基础ExpressionVisitor类以及参数替换如何工作的任何时候都是有用的。请注意,如何使用FuncCustomerQuery映射到Expression并应用于Customer数据库。

/// <summary>
/// An ExpressionVisitor for parameter substitution
/// </summary>
internal class ExpressionParameterSubstitute : ExpressionVisitor
{
    private readonly ParameterExpression from;
    private readonly Expression to;

    /// <summary>
    /// Creates a new instance of the <see cref="ExpressionParameterSubstitute"/> visitor
    /// </summary>
    public ExpressionParameterSubstitute(ParameterExpression from,Expression to)
    {
        this.from = from;
        this.to = to;
    }

    /// <summary>
    /// Visit a Lambda Expression
    /// </summary>
    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        if (node.Parameters.All(p => p != this.from))
            return node;

        // We need to replace the `from` parameter,but in its place we need the `to` parameter(s)
        // e.g. F<DateTime,Bool> subst F<Source,DateTime> => F<Source,bool>
        // e.g. F<DateTime,Bool> subst F<Source1,Source2,DateTime> => F<Source1,bool>

        if (to is LambdaExpression toLambda)
        {
            var substituteParameters = toLambda?.Parameters ?? Enumerable.Empty<ParameterExpression>();

            ReadOnlyCollection<ParameterExpression> substitutedParameters
                = new ReadOnlyCollection<ParameterExpression>(node.Parameters
                    .SelectMany(p => p == this.from ? substituteParameters : Enumerable.Repeat(p,1))
                    .ToList());

            var updatedBody = this.Visit(node.Body); // which will convert parameters to 'to'
            return Expression.Lambda(updatedBody,substitutedParameters);
        }
        else
        {
            // to is not a lambda expression so simple substitution can work
            ReadOnlyCollection<ParameterExpression> substitutedParameters
                = new ReadOnlyCollection<ParameterExpression>(node.Parameters
                    .Where(p => p != this.from)
                    .ToList());

            var updatedBody = this.Visit(node.Body); // which will convert parameters to 'to'

            if (substitutedParameters.Any())
                return Expression.Lambda(updatedBody,substitutedParameters);
            else
                return updatedBody;
        }
    }

    /// <summary>
    /// Visit a ParameterExpression
    /// </summary>
    protected override Expression VisitParameter(ParameterExpression node)
    {
        var toLambda = to as LambdaExpression;
        if (node == from) return toLambda?.Body ?? to;
        return base.VisitParameter(node);
    }
}

 public static Expression<Func<T,bool>> OrElse<T>(
    Expression<Func<T,bool>> expr1,Expression<Func<T,bool>> expr2)
{
    var parameter = Expression.Parameter(typeof (T));

    var leftVisitor = new ExpressionParameterSubstitute(expr1.Parameters[0],parameter);
    var left = leftVisitor.Visit(expr1.Body);

    var rightVisitor = new ExpressionParameterSubstitute(expr2.Parameters[0],parameter);
    var right = rightVisitor.Visit(expr2.Body);

    return Expression.Lambda<Func<T,bool>>(
        Expression.OrElse(left,right),parameter);
}

public static IDictionary<string,bool> Exists(IQueryable<Customer> customers,IEnumerable<CustomerQuery> data,Func<CustomerQuery,Expression<Func<Customer,bool>>> predicate)
{  
   Expression<Func<Customer,bool>> expression = x => false;
   foreach (var item in data)
   {
       var exprForOne = predicate.Invoke(item);
       expression = OrElse(expression,exprForOne);
   }

   var split = customers.GroupBy(expression).SelectMany(g => g.Select(c => new {c,g.Key})).ToDictionary(x => x.c.CustomerID,x => x.Key);
   return split;
}   

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-