System.Linq.Dynamic:使用列表(IEnumerable)参数

本文关键字:IEnumerable 参数 列表 Linq Dynamic System | 更新日期: 2023-09-27 18:23:56

我使用System.Linq.Dynamic来编写动态查询,但我不知道如何将列表(IEnumerable)参数传递给查询:以下是我想要实现的目标:

SELECT * FROM People WHERE Role IN ('Employee','Manager')

这是相同查询的Linq等价物:

from person in People where (new string[]{"Employee","Manager"}).Contains(person.Role)

所以我想我可以用动态Linq把这个查询写成:

People.Where("@0.Contains(Role)","(new string[]{'"Employee'",'"Manager'"})")

此版本也不起作用:

People.Where("(new string[]{"Employee","Manager"}).Contains(Role)")

所以问题来了:我如何应用DynamicLinqLibrary来处理列表和/或IEnumerable参数,比如上面的场景?

System.Linq.Dynamic:使用列表(IEnumerable)参数

Dynamic linq项目本机不支持'contains',我有同样的要求,必须下载源代码并对其进行修改以支持它。

我已经失去了跟上任何nuget更新的能力,但该解决方案现在可以满足我们的需求。我找不到我在哪里找到的,但我就是这样做的。

编辑dynamic.cs文件,并在第566行附近添加以下内容:

interface IEnumerableSignatures
{
    bool Contains(object selector); // Add this
    void Where(bool predicate);
    //...
// Then around line 628 add a new keyword:
static readonly string keywordOuterIt = "outerIt";
static readonly string keywordIt = "It";
//...
// above ParameterExpression It; add
ParameterExpression outerIt;
// In ParseIdentifier add
if (value == (object)keywordOuterIt) return ParseOuterIt();
//Then add that method
Expression ParseOuterIt()
{
    if (outerIt == null)
        throw ParseError(Res.NoItInScope);
    NextToken();
    return outerIt;
}
// In ParseAggreggate, add:
outerIt = it;
if (signature.Name == "Min" || signature.Name == "Max")
{
    typeArgs = new Type[] { elementType, args[0].Type };
}
else
{
    typeArgs = new Type[] { elementType };
}
if (args.Length == 0)
{
    args = new Expression[] { instance };
}
else
{   
    // add this section
    if (signature.Name == "Contains")
        args = new Expression[] { instance, args[0] };
    else
    {
        args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) };
    }
}
// In CreateKeyWords()
d.Add(keywordOuterIt, keywordOuterIt); // Add this

我不知道我们是否可以在这里上传源代码,但我一直在维护我自己的Dynamic.cs副本,并试图让它跟上nuget上的版本。如果你愿意,我很乐意上传。我只是不记得我是从哪里得到的,因为在Dynamic linq上搜索contains大多会产生错误的结果——指向字符串contains,而不是IEnumerable.contains。

Dynamic LINQ默认不支持Contains

你可以用老方法:

var roles = new[] { "Employee", "Manager" };
var predicate = new StringBuilder();
for (var i = 0; i < roles.Length; i++)
{
    string role = roles[i];
    predicate.AppendFormat("Role = @{0}", i);
    if (i < roles.Length) predicate.Append(" OR ");
}
People.Where(predicate.ToString(), role.Cast<object>().ToArray());

这里有一个问题:链接。在提到的问题中,还有其他替代品。

我知道这个老问题,但我花了很长时间才解决。使用最新的Dynamic linq在此处引用它:https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/314

因此:

List<string> ids = new List<string>(){ 1, 2, 3 };
List<string> stringIds = new List<string>(){ "test", "find", "something" };
var queryResults = context.someEntity.AsNoTracking();
queryResults = queryResults.Where("intColName in @0", ids);
queryResults = queryResults.Where("stringColName in @0", strings);
var results = await queryResults.ToListAsync();

这会生成类似sql的:

select cols where intColName in (1, 2, 3) AND stringColName IN (N'test', N'find', N'something')