我有一对Linq to SQL查询,它们包含相同的复杂Where子句,具体为:
where ((range.MinimumFrequency <= minFreq && minFreq <= range.MaximumFrequency)
|| (range.MinimumFrequency <= maxFreq && maxFreq <= range.MaximumFrequency)
|| (range.MinimumFrequency <= minFreq && maxFreq <= range.MaximumFrequency)
|| (range.MinimumFrequency >= minFreq && maxFreq >= range.MaximumFrequency))
而不是将这些代码复制并粘贴到所有地方,我想将其重构为可以共享的其他内容。我知道我不能用普通方法做到这一点,因为它无法翻译成SQL,但我也无法得到
表达&lt; FUNC&LT; ...&GT;&GT;
事情described here也可以。
如果我为了理解我的理智而简化了where子句,我想转向
where (range.MinumumFrequency < minFreq)
进入表达式,所以我尝试了:
public static Expression<Func<FreqRange, bool>> Overlaps(decimal minMHz, decimal maxMHz)
{
return (range => range.MinimumFrequency <= minMHz);
}
这似乎是编译,但我似乎无法使where语句工作,我尝试了以下内容:
where FreqRange.Overlaps(minMHz, maxMHz)
但是这给了我一个编译时错误:
无法隐式转换类型 'System.Linq.Expressions.Expression&GT;' 'bool'
有什么想法吗?另外,假设我们得到了这个工作,我可以简单地在Expression&lt;中扩展lambda表达式吗? Func&lt;&gt;&gt;包括其他条件?
答案 0 :(得分:2)
如果使用语言构建LINQ语法,则隐式声明lamba表达式 - lamba表达式为Expression<Func <>>
- 因此您不需要where子句要返回表达式,你需要 表达式。
e.g。
var q = from row in myTable
where row.a < aMax
select row.b;
// which translates to
var q = myTable.Where(row => row.a < aMax).Select(row => row.b);
现在你需要“缓存”row => row.a < aMax
- 而不仅仅是row.a < aMax
的值,如果愿意的话。所以,如果你要写这样的东西......
Expression<Func<?,bool>> cachedExpression = row => row.a < aMax;
var q = from row in myTable
where cachedExpression
select row.b;
嗯,你说的是“给定一行,确实是(给定一行,确实row.a小于aMax)”。这是无意义的,如果cachedExpression的类型为Expression<Func<?,bool>>
且myTable是LinqToSql提供的表,则无法编译。它会转化为这样的东西:
Expression<Func<?,bool>> cachedExpression = row => row.a < aMax;
//nonsense .Where:
var q = myTable.Where(row => cachedExpression).Select(row => row.b);
//effectively says this:
var q = myTable.Where(row => (row0 => row0.a < aMax)).Select(row => row.b);
现在,这是 legal ,因为linq查询提供程序可能实现具有非布尔值的whereclause,但它是一个非常奇怪的要做的事;当然没有标准的linq提供者(比如Linq to Sql)做这样的事情。
那么应该你做什么?类似的东西:
//not .Where(row=>cachedExpression)!
var q = myTable.Where(cachedExpression).Select(row => row.b);
//or, alternatively:
var q = from filteredRow in myTable.Where(cachedExpression)
select filteredRow.b;
答案 1 :(得分:1)
您还可以创建一个接收和发送IQueryable的方法。我已经使用了这些视图,但纯粹是在代码中。
public class WithProps
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public override string ToString()
{
return string.Format("{0}-{1}", Prop1, Prop2);
}
}
public static class Tools
{
public static IQueryable<WithProps> MyFilter(this IQueryable<WithProps> props)
{
return props.Where(p => p.Prop1 == "hi");
}
}
class Program
{
static void Main(string[] args)
{
var propList = new List<WithProps>()
{
new WithProps(){ Prop1="hi", Prop2="there"},
new WithProps(){ Prop1="hi", Prop2="bye"},
new WithProps(){ Prop1="hello", Prop2="world"},
new WithProps(){ Prop1="bye", Prop2="friend"}
};
var filtered = propList.AsQueryable().MyFilter();
Console.WriteLine("propList ===");
foreach (var item in propList)
Console.WriteLine(item.ToString());
Console.WriteLine("filtered ===");
foreach (var item in filtered)
Console.WriteLine(item.ToString());
}
}
...结果...
propList ===
hi-there
hi-bye
hello-world
bye-friend
filtered ===
hi-there
hi-bye