简体   繁体   English

Linq等效于分组选择

[英]Linq equivalent for grouping select

From a traditional SQL sentence like this: 从像这样的传统SQL语句中:

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

where CallTime is a datetime field, what I want is the oldest record belonging to each Owner . 其中CallTime是日期时间字段,我想要的是属于每个Owner的最旧记录。

How can I achieve this with Linq? 如何使用Linq做到这一点?

This was my attempt (I'm using Entity Framework and context is the entity instance): 这是我的尝试(我使用的是实体框架, 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) });

But I need also access to Id and Owner fields whereas now I have only access to CallTime . 但是我还需要访问IdOwner字段,而现在我只能访问CallTime

You cannot access Id in the given code because you are grouping by Owner and the Key to the group will be the Owner not the 'traffic' object. 您无法访问给定代码中的ID,因为您正在按所有者分组,并且该组的密钥将是所有者而不是“流量”对象。

If you group by traffic objects you need some way to tell the groupBy how to compare them properly (ie group by owner) This can be done with an IEqualityComparer 如果按流量对象分组,则需要某种方式来告诉groupBy如何正确比较它们(即按所有者分组)这可以通过IEqualityComparer来完成

eg 例如

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 };

                        });    }

this gives 这给

ID : Owner : MinCallTime

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

as the results. 作为结果。

Your SQL query doesn't look valid to me: you're using Id but not grouping by it. 您的SQL查询对我而言无效:您使用的是Id ,但未按其分组。 I assume that you wanted to group by Id and Owner ? 我假设您想按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();

If you want to get the oldest (smallest) ID instead of grouping by it: 如果要获取最旧的(最小的) 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();

// custQuery is an IEnumerable<IGrouping<string, Customer>> // 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;  

In that example you select the group 在该示例中,选择组

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM