【问题标题】:Expressions as parameter表达式作为参数
【发布时间】:2017-04-24 15:50:27
【问题描述】:

我使用表达式作为插入数据的参数(使用 EF):

public bool Exists(Expression<Func<V, bool>> predicate)
{
    return _dbContext.Set<V>().Any(predicate);
}

public void AddIfNotExists(V entity, Expression<Func<V, bool>> predicate)
{
    if (!Exists(predicate))
        Add(entity);
}

我有一个名为 Synchronize 的方法,使用不同的表达式:

protected void Synchronize<T>(string resource, Expression<Func<T, T, bool>> predicate) where T : class
{
    var list = _context.RestClient.Get<List<T>>(resource);

    using (var repo = new Repository<GmaoContext, T>())
    {
        list.ForEach(x =>
        {
            repo.AddIfNotExists(x, y => predicate.Compile().Invoke(x, y));
        });

        repo.Save();
    }
}

我的方法 Synchronize 需要两个参数:

Synchronize<ClientLivraison>("clientlivraison", (x, y) => x.IdClientJuridique == y.IdClientJuridique && x.IdClientLivraison == y.IdClientLivraison);

在运行时,我有这个异常:

System.NotSupportedException:'LINQ to Entities 无法识别方法 'Boolean Invoke(Manuloc.Gmao.SynchroDb.Entity.Origine, Manuloc.Gmao.SynchroDb.Entity.Origine)' 方法,并且此方法不能被翻译成商店表达式。'

我的问题,如何转换/传递我的表达式

Expression<Func<T, T, bool>>

Expression<Func<T, bool>>

【问题讨论】:

  • 您没有 LINQ 表达式作为参数,您只有一个表达式。它绝不是 LINQ 特有的。
  • LINQ to EF query 被转换为 SQL。您使用的 lambda 和表达式不会被执行,它们会被转换为 SQL。该错误表明您提供的 lambda 无法 被转换为 SQL。具体来说,Compile().Invoke() 无法转换为 SQL。只需删除它。
  • 如果我删除 Compile().Invoke(),repo.AddIfNotExists(x, y =&gt; func(x, y)); 我有一个例外:'LINQ to Entities 不支持 LINQ 表达式节点类型'Invoke'.
  • 您的代码可能存在比相等比较的性能更严重的性能问题。通过在这样的循环中调用 AddIfNotExists,您可能正在执行 N 个单独的命令,从而导致 N 次到数据库的往返。这会导致延迟 过多的登录 - 最坏的情况,慢 N 倍。 EF 已经支持附加分离的实体
  • @SpeedNeo 那么您必须拨打任何其他Invoke() 电话。这些不是自己出现的。无论如何,您的代码是将新项目添加到上下文的一种相当复杂的方式。 PS WHERE 子句由 .Where() 调用生成。你没有这样的电话。你的 AddIfNotExists 试图模仿 Where(predicate)

标签: c# entity-framework linq-to-entities


【解决方案1】:

可以通过使用自定义ExpressionVisitorExpression.Lambda 方法替换第一个或第二个参数Expression&lt;Func&lt;T, T, bool&gt;&gt; 转换为Expression&lt;Func&lt;T, bool&gt;&gt;

但更简单、更自然的方法是更改​​ Synchronize 方法参数

Expression<Func<T, T, bool>> predicate

Func<T, Expression<Func<T, bool>>> predicateFactory>

即带有参数T 的函数委托,调用时根据传递的参数返回Expression&lt;Func&lt;T, bool&gt;&gt;

从调用者的角度来看,这将是一个改变

(x, y) => x.IdClientJuridique == y.IdClientJuridique && x.IdClientLivraison == y.IdClientLivraison

x => y => x.IdClientJuridique == y.IdClientJuridique && x.IdClientLivraison == y.IdClientLivraison

而实现只是替换

repo.AddIfNotExists(x, y => predicate.Compile().Invoke(x, y));

repo.AddIfNotExists(x, predicateFactory(x));

这是整个方法:

protected void Synchronize<T>(string resource, Func<T, Expression<Func<T, bool>>> predicateFactory) where T : class
{
    var list = _context.RestClient.Get<List<T>>(resource);

    using (var repo = new Repository<GmaoContext, T>())
    {
        list.ForEach(x =>
        {
            repo.AddIfNotExists(x, predicateFactory(x));
        });

        repo.Save();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多