Linq相当于分组选择

时间:2012-07-17 10:52:31

标签: c# mysql linq entity-framework

来自这样的传统SQL语句:

SELECT Id, Owner, MIN(CallTime) 
FROM traffic 
WHERE CallType = "IN" 
GROUP BY Owner;

其中CallTime是日期时间字段,我想要的是属于每个Owner的最旧记录。

如何使用Linq实现这一目标?

这是我的尝试(我正在使用实体框架,context是实体实例):

var query = context.traffic.Where(t => t.CallType == "IN");
var results = query
    .GroupBy(t => t.Owner)
    .Select(g => new { CallTime = g.Min(h => h.CallTime) });

但我还需要访问IdOwner字段,而现在我只能访问CallTime

3 个答案:

答案 0 :(得分:3)

您无法在给定代码中访问ID,因为您按所有者进行分组,而该组的密钥将是所有者而非“流量”对象。

如果按流量对象分组,则需要某种方式告诉groupBy如何正确比较它们(即按所有者分组)这可以通过IEqualityComparer来完成

e.g。

private class Traffic {
    public int Id { get; set; }
    public string Owner { get; set; }
    public DateTime CallTime { get; set; }
}

private class TrafficEquaityComparer : IEqualityComparer<Traffic> {
    public bool Equals(Traffic x, Traffic y) {
            return x.Owner == y.Owner;
    }

    public int GetHashCode(Traffic obj) {
        return obj.Owner.GetHashCode();
    }
}


private static TrafficEquaityComparer TrafficEqCmp = new TrafficEquaityComparer();

private Traffic[] src = new Traffic[]{
   new Traffic{Id = 1, Owner = "A", CallTime = new DateTime(2012,1,1)},  // oldest
   new Traffic{Id = 2, Owner = "A", CallTime = new DateTime(2012,2,1)},
   new Traffic{Id = 3, Owner = "A", CallTime = new DateTime(2012,3,1)},
   new Traffic{Id = 4, Owner = "B", CallTime = new DateTime(2011,3,1)},
   new Traffic{Id = 5, Owner = "B", CallTime = new DateTime(2011,1,1)},   //oldest
   new Traffic{Id = 6, Owner = "B", CallTime = new DateTime(2011,2,1)},
};

[TestMethod]
public void GetMinCalls() {
     var results = src.GroupBy(ts => ts, TrafficEqCmp)
                        .Select(grp => {
                            var oldest = grp.OrderBy(g => g.CallTime).First();
                            return new { Id = oldest.Id, 
                                         Owner = grp.Key.Owner, 
                                         CallTime = oldest.CallTime };

                        });    }

这给出了

ID : Owner : MinCallTime

1 :    A   :  (01/01/2012 00:00:00)
5 :    B   :  (01/01/2011 00:00:00)

作为结果。

答案 1 :(得分:2)

您的SQL查询对我来说看起来不合适:您使用的是Id,但没有使用它进行分组。我假设您想按IdOwner进行分组?

var results = query
     .GroupBy(t => new {Id = t.Id, Owner = t.Owner})
     .Select(g => new { Id = g.Key.Id, Owner = g.Key.Owner, CallTime = g.Min(h => h.CallTime) })
     .ToList();

如果您想获得最早的(最小的)ID而不是按照它进行分组:

var results = query
     .GroupBy(t => t.Owner)
     .Select(g => new { Id = g.Min(x => x.Id), Owner = g.Key, CallTime = g.Min(h => h.CallTime) })
     .ToList();

答案 2 :(得分:0)

// custQueryIEnumerable<IGrouping<string, Customer>>

var custQuery =  
    from cust in customers  
    group cust by cust.City into custGroup  
    where custGroup.Count() > 2  
    orderby custGroup.Key  
    select custGroup;  

在该示例中,您选择了组