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参数,比如上面的场景?
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')