在LINQ查询中执行条件'if'语句'where'语句
我试图找出一种方法来查询我的数据模型中的一个对象,并且只包含那些非空的参数。如下图所示:在LINQ查询中执行条件'if'语句'where'语句
public List<Widget> GetWidgets(string cond1, string cond2, string cond3)
{
MyDataContext db = new MyDataContext();
List<Widget> widgets = (from w in db.Widgets
where
... if cond1 != null w.condition1 == cond1 ...
... if cond2 != null w.condition2 == cond2 ...
... if cond3 != null w.condition3 == cond3 ...
select w).ToList();
return widgets;
}
由于部件表可以得到非常大的,我想避免这样做:
public List<Widget> GetWidgets(string cond1, string cond2, string cond3)
{
MyDataContext db = new MyDataContext();
List<Widget> widgets = db.Widgets.ToList();
if(cond1 != null)
widgets = widgets.Where(w => w.condition1 == cond1).ToList();
if(cond2 != null)
widgets = widgets.Where(w => w.condition2 == cond2).ToList();
if(cond3 != null)
widgets = widgets.Where(w => w.condition3 == cond3).ToList();
return widgets;
}
我看了几个例子,但没有真正看到任何匹配我需要做的事情。
要避免实际执行查询,直到你准备什么:
public List<Widget> GetWidgets(string cond1, string cond2, string cond3)
{
MyDataContext db = new MyDataContext();
var widgets = db.Widgets;
if(cond1 != null)
widgets = widgets.Where(w => w.condition1 == cond1);
if(cond2 != null)
widgets = widgets.Where(w => w.condition2 == cond2);
if(cond3 != null)
widgets = widgets.Where(w => w.condition3 == cond3);
return widgets.ToList();
}
注意ToList
呼叫的方式去除。直到您开始迭代查询才会执行查询。调用ToList
将强制执行该操作,以便将结果放入List<>
并返回。我甚至会建议该方法的返回值更改为IEnumerable<Widget>
以及跳过到底ToList
电话:
public IEnumerable<Widget> GetWidgets(string cond1, string cond2, string cond3)
{
MyDataContext db = new MyDataContext();
var widgets = db.Widgets;
if(cond1 != null)
widgets = widgets.Where(w => w.condition1 == cond1);
// [...]
return widgets;
}
这样调用代码获取来决定何时执行查询(它甚至可以添加更多的条件在此之前)。
这样的事情呢?
IEnumerable<Widget> condQuery = (from w in db.Widgets);
if(cond1 != null) condQuery = condQuery.Where(w=> w.condition1 == cond1);
if(cond2 != null) condQuery = condQuery.Where(w=> w.condition2 == cond2);
etc ...?
不编译。 – Timwi 2010-09-21 13:59:52
你实际上要求调度员在 linq查询。 Where
方法接受一个谓词,因此您可以在创建查询之前构建谓词。
- 编辑 - 起初,我认为它更容易,写了一些甚至没有编译的伪代码。现在,无论如何,我想我明白了。此代码将起作用;它将构建where子句与应用它分开。
static Predicate<Widget> combine(
Predicate<Widget> existing,
Predicate<Widget> condition)
{
var newpred = new Predicate<Widget>(w=> existing(w) && condition(w));
return newpred;
}
,并使用类似的这种 '建筑' 功能:
static void Main(string[] args)
{
string cond1 = "hi";
string cond2 = "lo";
string cond3 = null;
var pr = new Predicate<Widget>((Widget w) => true);
if (cond1 != null) pr = combine(pr, w => w.condition1 == cond1);
if (cond2 != null) pr = combine(pr, w => w.condition2 == cond2);
if (cond3 != null) pr = combine(pr, w => w.condition3 == cond3);
我有一个小帮手阵列进行了测试:
var widgets = new Widget[]{
new Widget(){ condition1 = "" },
new Widget(){ condition1 = "hi", condition2 = "lo" }
};
var selected = widgets.Where((w) => pr(w));
foreach (var w in selected) {
Console.WriteLine(w);
}
请使用 “或门”:前言我们小部件条件测试用“||”并检查我们是否使用该条件。如果我们不是,那么“或”的后半部分就不会被评估。这就是为什么它是一个大门 - 如果第一部分评估为真,我们就不会再进一步了。
如果我正在写它,我会像下面这样做。我用var syntatic糖来保存LINQ查询并将ToList()移到最后。
public List<Widget> GetWidgets(string cond1, string cond2, string cond3)
{
MyDataContext db = new MyDataContext();
var widgets = from w in db.Widgets
where (cond1 == null || w.condition1 == cond1)
&& (cond2 == null || w.condition2 == cond2)
&& (cond3 == null || w.condition3 == cond3)
select w;
return widgets.ToList();
}
编辑:语法
我们可以用很简单的方法如下图所示。
(from e in employee
join d in departments on e.departmentId equals d.departmentId
Select new {
e.name,
d.name,
getEmployeeContacts(e)
}
//return active contact if not return first . This is same like if else along with null check
private contact getEmployeeContacts(Employee e)
{
return e.Contacts.FirstOrDefault(x => x.Active == 1) ?? e.Contacts.FirstOrDefault();
}
是否由JIT编译器在结果查询中删除条件?或者linq'保证'一些优化? – xtofl 2010-09-21 16:51:43
@xtofl:不确定你的意思?你想摆脱哪些条件? – 2010-09-21 17:49:02
如果条件不满足,它们不会添加到表达式树中。 – Michael 2010-09-22 02:02:43