Tam*_*nut 6 c# sql-server entity-framework expression-trees
我在SQL Server中有以下表:
ProductAttribute
nvarchar(100)
nvarchar(200)
这是通过Entity Framework映射到我的类:
public class ProductAttribute
{
public string Name {get;set;}
public string Value {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
有些行ProductAttributes
具有以下形式:
{Name: "RAM", Value: "8 GB"}, {Name: "Cache", Value: "3000KB"}
我需要动态构造一个可转换为SQL的ExpressionTree,它可以执行以下操作:
如果值以数字后跟或不是字母数字字符串开头,请提取数字并将其与给定值进行比较
double value = ...;
Expression<Func<ProductAttribute, bool>> expression = p =>
{
Regex regex = new Regex(@"\d+");
Match match = regex.Match(value);
if (match.Success && match.Index == 0)
{
matchExpression = value.Contains(_parserConfig.TokenSeparator) ?
value.Substring(0, value.IndexOf(_parserConfig.TokenSeparator)) :
value;
string comparand = match.Value;
if(double.Parse(comparand)>value)
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)真正讨厌的是我需要动态构造这个表达式树.
到目前为止,我已经管理了这个(它将值视为十进制而不是字符串,因此它甚至不会尝试执行整个正则表达式的东西):
private Expression GenerateAnyNumericPredicate(
Type type,
string valueProperty,
string keyValue,
double value) {
ParameterExpression param = Expression.Parameter(type, "s");
MemberExpression source = Expression.Property(param, valueProperty);
ConstantExpression targetValue = GetConstantExpression(value, value.GetType());
BinaryExpression comparisonExpression = Expression.GreaterThan(source, targetValue);
return Expression.Lambda(comparisonExpression, param);
}
Run Code Online (Sandbox Code Playgroud)
编辑:在下面提供的帮助下,这适用:
Expression<Func<ProductSpecification, bool>> expo = ps=> ps.Value.Substring(0, (SqlFunctions.PatIndex("%[^0-9]%", ps.Value + ".") ?? 0) - 1) == "1000";
Run Code Online (Sandbox Code Playgroud)
但我还需要一个强制转换,然后进行数字比较:
Expression<Func<ProductSpecification, bool>> expo = ps=> double.Parse(ps.Value.Substring(0, (SqlFunctions.PatIndex("%[^0-9]%", ps.Value + ".") ?? 0) - 1)) > 1000;
Run Code Online (Sandbox Code Playgroud)
显然这不能转换为SQL : double.Parse()
.
我怎样才能构建转换器,以便可以从我的Expression中解析为SQL?
我认为 Yacoub Massad 询问 SQL 应该是什么样子是有道理的。如果无法编写执行查询的 SQL,怎么可能有一个表达式树可以转换为所需的 SQL?
主要问题是 SQL Server 本身不支持正则表达式。您可以将 CLR 函数导入数据库并在 UDF 中使用它,但这并不是使其与 EF 一起使用的最简单方法。
因此,再次从对可以完成这项工作的 SQL 进行映像开始。
现在我发现这个小宝石可以从字符串中提取数字(左)部分:
select left(@str, patindex('%[^0-9]%', @str+'.') - 1)
Run Code Online (Sandbox Code Playgroud)
这将从“3000KB”返回“3000”。
幸运的是,我们可以SqlFunctions.PatIndex
在 LINQ 语句中重现这一点:
from pa in context.ProductAttributes
select pa.Value.Substring(0, (SqlFunctions.PatIndex("%[^0-9]%", pa.Value + ".") ?? 0) - 1)
Run Code Online (Sandbox Code Playgroud)
这显然会从你的例子中8
返回3000
。
现在困难的部分已经完成,您可以使用此结果将谓词应用于此数字部分:
from pa in context.ProductAttributes
let numPart = pa.Value.Substring(0, (SqlFunctions.PatIndex("%[^0-9]%", pa.Value + ".") ?? 0) - 1)
where numPart .... // go ahead
Run Code Online (Sandbox Code Playgroud)
您将看到,每次numPart
在 LINQ 语句中使用时,整个PatIndex
内容都会在 SQL 语句中重复(即使您将其包装在子查询中)。不幸的是,这就是 SQL 的工作原理。它无法存储临时的语句内结果。嗯,语言规范已经有 40 多年的历史了,一点也不差。
归档时间: |
|
查看次数: |
383 次 |
最近记录: |