怎么做linq中的“case when”条件?

时间:2013-05-30 16:29:30

标签: sql linq

基本上我有一些与此类似的数据表

| ItemId | RuleId | IsActive |
------------------------------
| ItemA  | RuleA  | FALSE    |
------------------------------
| NULL   | RuleA  | TRUE     |
------------------------------
| ItemC  | RuleA  | TRUE     |
------------------------------
| ItemA  | RuleB  | FALSE    |
------------------------------
| NULL   | RuleB  | TRUE     |
------------------------------

我希望得到这样的结果

表示项目

| ItemId | RuleId | IsActive |
------------------------------
| ItemA  | RuleA  | FALSE    |
------------------------------
| ItemA  | RuleB  | FALSE    |
------------------------------

表示项目b

| ItemId | RuleId | IsActive |
------------------------------
| NULL   | RuleA  | TRUE     |
------------------------------
| NULL   | RuleB  | TRUE     |
------------------------------

表示项目c

| ItemId | RuleId | IsActive |
------------------------------
| ItemC  | RuleA  | TRUE     |
------------------------------
| NULL   | RuleB  | TRUE     |
------------------------------

基本上如果有特定规则,则使用指定的,否则使用默认规则设置为null作为itemId

如何在linq中实现这一目标?

提前致谢

编辑:感谢造型,@ lazyberezovsky。 @dasblinkenlight我也没有sql的查询。我确实需要以linq方式,但如果有人能给我一些建议如何以sql方式获得结果,那也很有帮助。

3 个答案:

答案 0 :(得分:1)

这不是最漂亮的LINQ查询,但这里有一个完整的代码示例

//the sample data as provided by the OP
var rules = new []
{
    new { ItemId = "ItemA", RuleId = "RuleA", IsActive = false },
    new { ItemId = (string)null, RuleId = "RuleA", IsActive = true },
    new { ItemId = "ItemC", RuleId = "RuleA", IsActive = true },
    new { ItemId = "ItemA", RuleId = "RuleB", IsActive = false },
    new { ItemId = (string)null, RuleId = "RuleB", IsActive = true },
};

//the items that we want to get the rules for
var items = new [] { "ItemA", "ItemB", "ItemC", };

//get the rules for all of the items
var query = from i in items
            let itemRules = from r in rules
                            //we need to prefer rules that match our id
                            orderby r.ItemId ?? "" descending
                            //match on id or null
                            where (r.ItemId ?? i) == i                            
                            group r by r.RuleId into grouping                        
                            //take the best match
                            select grouping.First()
            select new
            {
                i,
                itemRules,
            };

这是输出

enter image description here

我认为这不适用于LINQ to SQL,但它肯定适用于LINQ to Objects。当我有时间构建测试数据库时,我会看看是否可以使用LINQ to SQL的版本。

答案 1 :(得分:0)

您可以在LINQ中使用任何语言构造(它不会被称为语言集成查询)。例如,如果您使用VB.NET - 您可以直接在LINQ查询

中使用CHOOSE function

答案 2 :(得分:0)

您可以按RuleId对所有项目进行分组,然后从每个组中选择第一项,该项目已指定itemId。如果没有这样的项目,则创建并返回默认项目:

from i in items
group i by i.RuleId into g
select g.FirstOrDefault(x => x.ItemId == itemId) ?? 
       new Item { ItemId = null, RuleId = g.Key, IsActive = true }

此查询将用于内存中的项目。但是您无法在服务器端创建新的默认项目 - 您将收到错误

  

无法构造实体或复杂类型“Item”   在LINQ to Entities查询中。

因此,返回匿名类型而不是项目,并在内存中构造项目:

(from i in context.Items
 group i by i.RuleId into g
 let item = g.FirstOrDefault(x => x.ItemId == itemId)
 select new
 {
     ItemId = item == null ? null : itemId, // default if not found
     RuleId = g.Key,
     IsActive = item == null ? true : item.IsActive
 })
.AsEnumerable() // move to memory
.Select(i => new Item { 
     ItemId = i.ItemId, 
     RuleId = i.RuleId, 
     IsActive = i.IsActive 
});

适用于EF。