【问题标题】:C# - How to use Expression<Func> with parametrs in LINQ whereC# - 如何在 LINQ 中将 Expression<Func> 与参数一起使用
【发布时间】:2020-01-21 13:48:13
【问题描述】:

任务:我需要在LINQ's 中提供一些带参数的表达式,从database 获取一些数据,但上面有错误 这个工作表达式的例子:

var shopExp = GetPersonForShop(PersonTypeIds.Director, new Guid("adda423f-8c38-40e0-9f39-6deceb787bc0")); // id
Where(shopExp) 

但我需要动态分配 id,但上面出现错误:

_repository.Persons
.Where(GetPersonForShop(PersonTypeIds.Director, person.PersonId)

得到错误:

{"无法将 'System.Linq.Expressions.InstanceMethodCallExpression2' 类型的对象转换为 'System.Linq.Expressions.LambdaExpression' 类型。"}

where(linq) 的函数看起来如何:

private Expression<Func<Person, bool>> GetPersonForShop(PersonTypeIds personTypeId, Guid personId)
        {
            return person => person .PeronTypeId== (int) personTypeId && person .PersonId == personId;
        }

这是大概的样子,只是改变参数代码的名称

如何将带参数的表达式添加到Where 子句??

【问题讨论】:

  • GetPersonForShop的签名是什么?
  • EF/EF Core 已经允许动态查询。有多个答案显示如何动态添加 Where 子句。我怀疑真正的问题是在 EF 之上添加一个“通用”存储库并失去执行 LINQ 查询的能力
  • 我添加了有关此任务的更多信息。是的,我知道 lambda 是如何工作的,我需要将带参数的表达式(返回表达式的函数)移动到 'where' linq 方法中。
  • 我很困惑。首先您使用GetPersonForShop,然后向我们展示具有相同(明显)签名的GetKpisForEntity 方法。您不只是对这两个方法名称感到困惑吗?你的代码中也有很多错别字,这让我们无法判断你是在写问题还是自己写代码的时候打错了。
  • 据我所知,这应该对您有所帮助:[ref] stackoverflow.com/questions/14297633/…

标签: c# sql linq .net-core ef-core-3.0


【解决方案1】:

Lambda 表达式使用=&gt; 表示法。试试这样的:

var idToFind = new Guid("adda423f-8c38-40e0-9f39-6deceb787bc0");

var result = _repository.Persons
    .Where(p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind);

在此表达式中,p 表示 Persons 表中的每个 Person 记录,并使用其后面的布尔表达式进行逐一比较。

根据您的数据源,每个p 的比较将由.NET 在内存中完成,或者将使用从布尔表达式构造的SQL WHERE 子句在您的数据库中进行。最后一个是最佳选择,因为这意味着在进行比较之前不必将整个 Persons 表传输到 .NET 内存中。

更新 - 要多次应用相同的条件而不在您的代码中重复它,同时仍然保持 LINQ 到 SQL 转换的优势不变,您可以将条件放在 Expression&lt;Func&lt;Person, bool&gt;&gt; 对象中并然后多次使用:

Expression<Func<Person, bool>> expression =
    p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind;

var result1 = datasource1.Where(expression);
var result2 = datasource2.Where(expression);
var result3 = datasource3.Where(expression);

或者通过产生 Expression对象的方法:

var result1 = datasource1.Where(GetExpression(idToFind));
var result2 = datasource2.Where(GetExpression(idToFind));
var result3 = datasource3.Where(GetExpression(idToFind));

public Expression<Func<Person, bool>> GetExpression(Guid idToFind)
{
    return p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind;
}

或者您也可以使用辅助方法:

var result1 = FilterByTypeAndId(datasource1, idToFind);
var result2 = FilterByTypeAndId(datasource2, idToFind);
var result3 = FilterByTypeAndId(datasource3, idToFind);

public IQueryable<Person> FilterByTypeAndId(IQueryable<Person> datasource, Guid idToFind)
{
    return datasource.Where(p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind);
}

【讨论】:

  • 这个问题在代码中的 11 处重复出现,这就是为什么我想使用表达式来简化它。更多,我有更复杂的选择逻辑,但不能使用因为想要使用没有参数的表达式
【解决方案2】:

根据之前的回复,我将给你一些替代方案和建议。

var idToFind = new Guid("adda423f-8c38-40e0-9f39-6deceb787bc0");

var result = _repository
    .Persons
    .Where(p => p.TypeId == PersonTypeIds.Director)
    .Where(p => p.PersonId == idToFind)
    .ToList();

首先分两步执行 where 子句,然后添加 ToList() 和 ToList(),您将处理非常有用的集合和 LINQ。通过分两步执行 where 子句,更便于阅读。

【讨论】:

    猜你喜欢
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    相关资源
    最近更新 更多