使用outerIt生成动态Linq查询

时间:2017-04-07 07:27:53

标签: c# entity-framework linq dynamic-linq

我正在使用 Microsoft的Dynamic Linq(System.Linq.Dynamic)库在运行时生成一些查询。这对我来说很有用,但对于一个特定的场景。

简化方案 - 我正在尝试查询所有具有某些特定标记的声明,这些标记已由用户选择且其余额大于某个数字。

static void Main(string[] args)
    {
        var claims = new List<Claim>();
        claims.Add(new Claim { Balance = 100, Tags = new List<string> { "Blah", "Blah Blah" } });
        claims.Add(new Claim { Balance = 500, Tags = new List<string> { "Dummy Tag", "Dummy tag 1" } });

        // tags to be searched for
        var tags = new List<string> { "New", "Blah" };
        var parameters = new List<object>();
        parameters.Add(tags);

        var query = claims.AsQueryable().Where("Tags.Any(@0.Contains(outerIt)) AND Balance > 100", parameters.ToArray());
    }

public class Claim
{
    public decimal? Balance { get; set; }
    public List<string> Tags { get; set; }
}

此查询引发错误:

  

未处理的类型&#39; System.Linq.Dynamic.ParseException&#39;发生在System.Linq.Dynamic.dll中   附加信息:没有财产或字段&#39;余额&#39;存在于&#39;字符串&#39;

动态linq解析器似乎试图在Tag上找到Balance属性,而不是在Claim对象上找到。

  • 我试图在Dynamic Linq中使用 outerIt,innerIt,It 关键字,但似乎没有任何效果。
  • 更改序列有效,但这对我来说不是一个选项,因为在实际应用中,过滤器,运算符和模式将是动态的(由最终用户配置)。
  • 用括号()括起条件,也没有帮助。
  • 解决方法 - 为所选的每个标记创建一个简单的包含条件,例如Tags.Contains(&#34; New&#34;)OR Tags.Contains(&#34; Blah&#34;)等。但在实际的应用程序中,它会导致每个条件的真正复杂/错误查询并杀死性能。

我可能会遗漏某些东西,或者这可能是图书馆中的一个错误。

如果有人能帮助我,我真的很感激。

2 个答案:

答案 0 :(得分:1)

找到ParseAggregate中的错误...如果有多个级别,推送itouterIt并返回不起作用。该代码假设itouterIt在重置之前不会被第三方更改(技术上代码不是可重入的)。您可以尝试System.Linq.Dynamic的其他变体(有两个或三个变体)。可能有些变种已经修复了它。

或者您可以从链接的站点获取代码并在代码中重新编译它(最终&#34;原始&#34; System.Linq.Dynamic是单个cs文件)并且您可以像这样修补它:

Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
{
    // Change starts here
    var originalIt = it;
    var originalOuterIt = outerIt;
    // Change ends here

    outerIt = it;
    ParameterExpression innerIt = Expression.Parameter(elementType, elementType.Name);
    it = innerIt;
    Expression[] args = ParseArgumentList();

    // Change starts here
    it = originalIt;
    outerIt = originalOuterIt;
    // Change ends here

    MethodBase signature;
    if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)

我已经在项目的github中提出了建议的错误修复问题。

答案 1 :(得分:0)