使用 outerIt 生成动态 Linq 查询
Generate Dynamic Linq query using outerIt
我正在使用 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; }
}
此查询引发错误:
An unhandled exception of type 'System.Linq.Dynamic.ParseException' occurred in System.Linq.Dynamic.dll
Additional information: No property or field 'Balance' exists in type 'String'
动态 linq 解析器似乎试图在 Tag 而不是 Claim 对象上找到余额 属性。
- 我尝试在 Dynamic Linq 中使用 outerIt、innerIt、It 关键字,但 none 似乎有效。
- 更改顺序可行,但这对我来说不是一个选项,因为在实际应用程序中,过滤器、运算符和模式将是动态的(由最终用户配置)。
- 将条件装箱在括号 () 中,也无济于事。
- 解决方法 - 为每个选定的标签创建一个简单的包含条件,例如Tags.Contains("New") 或 Tags.Contains("Blah") 等。但在实际应用程序中,它会导致每个条件的查询非常复杂/错误,并降低性能。
我可能遗漏了一些东西,或者这可能是库中的错误。
如果有人能帮助我,我将不胜感激。
在 ParseAggregate 中发现 a/the 错误...如果有多个级别,it
→outerIt
的推送和返回将不起作用。该代码假定 it
和 outerIt
在重置之前不会被第三方更改(从技术上讲,该代码不可重入)。您可以尝试 System.Linq.Dynamic
的其他变体(其中有两个或三个变体)。可能一些变体已经修复了它。
或者您可以从链接站点获取代码并在您的代码中重新编译它(最终 "original" 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 中打开了一个问题,其中包含建议的错误修复。
这似乎在我的版本中工作正常:System.Linq.Dynamic.Core
我正在使用 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; }
}
此查询引发错误:
An unhandled exception of type 'System.Linq.Dynamic.ParseException' occurred in System.Linq.Dynamic.dll Additional information: No property or field 'Balance' exists in type 'String'
动态 linq 解析器似乎试图在 Tag 而不是 Claim 对象上找到余额 属性。
- 我尝试在 Dynamic Linq 中使用 outerIt、innerIt、It 关键字,但 none 似乎有效。
- 更改顺序可行,但这对我来说不是一个选项,因为在实际应用程序中,过滤器、运算符和模式将是动态的(由最终用户配置)。
- 将条件装箱在括号 () 中,也无济于事。
- 解决方法 - 为每个选定的标签创建一个简单的包含条件,例如Tags.Contains("New") 或 Tags.Contains("Blah") 等。但在实际应用程序中,它会导致每个条件的查询非常复杂/错误,并降低性能。
我可能遗漏了一些东西,或者这可能是库中的错误。
如果有人能帮助我,我将不胜感激。
在 ParseAggregate 中发现 a/the 错误...如果有多个级别,it
→outerIt
的推送和返回将不起作用。该代码假定 it
和 outerIt
在重置之前不会被第三方更改(从技术上讲,该代码不可重入)。您可以尝试 System.Linq.Dynamic
的其他变体(其中有两个或三个变体)。可能一些变体已经修复了它。
或者您可以从链接站点获取代码并在您的代码中重新编译它(最终 "original" 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 中打开了一个问题,其中包含建议的错误修复。
这似乎在我的版本中工作正常:System.Linq.Dynamic.Core