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

时间:2014-09-22 08:20:21

标签: c# linq

我正在使用System.Linq.Dynamic来编写动态查询,但我无法弄清楚如何将list(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)")

所以问题是:我如何应用Dynamic Linq Library来处理列表和/或IEnumerable参数,例如上面的场景?

3 个答案:

答案 0 :(得分:2)

动态linq项目不支持'包含'本地,我有相同的要求,不得不下载源并修改它以支持它。

我已经失去了跟上任何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版本保持最新版本。如果你愿意,我很乐意上传它。我只是不记得我得到了所有这些,因为在动态linq上搜索包含主要产生错误的结果 - 指向字符串包含,而不是IEnumerable.contains。

答案 1 :(得分:1)

默认情况下,动态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());

以下是关于此的问题:link。在提到的问题中,还有其他替代品。

答案 2 :(得分:0)

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

所以:

final bytes = UriData.parse(base64Result).contentAsBytes();

这将生成 sql 如下:

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();