我有一张桌子,我们称之为Record。含: ID(int)| CustID(int)|时间(日期时间)|数据(varchar)
我需要每个客户的最新(最新)记录:
SQL
select * from record as i group by i.custid having max(id);
LINQ版本1
dgvLatestDistinctRec.DataSource = from g in ee.Records
group g by g.CustID into grp
select grp.LastOrDefault();
这会引发错误:
System.NotSupportedException未被用户代码Message = LINQ处理 to Entities无法识别方法'Faizan_Kazi_Utils.Record LastOrDefault [实录 ](System.Collections.Generic.IEnumerable`1 [Faizan_Kazi_Utils.Record ])'方法,这个方法无法翻译成商店 表达。源= System.Data.Entity的
LINQ第2版
var list = (from g in ee.Records
group g by g.CustID into grp
select grp).ToList();
Record[] list2 = (from grp in list
select grp.LastOrDefault()).ToArray();
dgvLatestDistinctRec.DataSource = list2;
这是有效的,但是效率很低,因为它将数据库中的所有记录加载到内存中,然后只提取每个组的最后一个(最近的成员)。
是否有任何LINQ解决方案能够提高上述SQL解决方案的效率和可读性?
答案 0 :(得分:4)
更新
var results = (from rec in Record group rec by rec.CustID into grp
select new
{
CustID = grp.Key,
ID = grp.OrderByDescending(r => r.ID).Select(x => x.ID).FirstOrDefault(),
Data = grp.OrderByDescending(r => r.ID).Select(x => x.Data).FirstOrDefault()
}
);
所以我做了一个测试表并写了一个Linq - > SQL Query将完全满足您的需求。看看这个,让我知道你的想法。如果这个查询被缩放,唯一要记住的是我相信它会在select new中分组后为每个CustID记录运行一个查询。唯一可以确定的方法是在运行查询信息时运行SQL Tracer .. http://www.foliotek.com/devblog/tuning-sql-server-for-programmers/
原件:
你可以这样做吗?from g in ee.Records where g.CustID == (from x in ee.Records where (g.CustID == x.CustID) && (g.ID == x.Max(ID)).Select(r => r.CustID))
这都是伪代码,但希望你能得到这个想法。
答案 1 :(得分:2)
我可能来不及帮助解决您的问题,但我遇到了类似的问题,并且可以通过以下查询获得所需的结果:
from g in ee.Records
group g by g.CustID into grp
from last in (from custRec in grp where custRec.Id == grp.Max(cr => cr.Id) select custRec)
select last
答案 2 :(得分:1)
我认为grp.LastOrDefault()是一个C#函数,是SQL不知道的。 LINQ将您的查询转换为SQL查询,以便您的数据库服务器了解。您可能希望尝试创建存储过程,或者以其他方式过滤掉您要查找的内容。
第二个查询的工作原因是因为LINQ to SQL返回一个列表,然后在C#列表上执行LINQ查询(以过滤掉你需要的内容),它实现了IEnumerable / IQueryable接口并理解了grp。 LastOrDefault()。
答案 3 :(得分:1)
如果用简单的Last()替换LastOrDefault()怎么办? (是的,你必须检查你的记录表是不是空的)
因为我无法看到MySQL如何返回“默认”组。这不是可以简单地转换为SQL的东西。
答案 4 :(得分:0)
我有另一个想法:
// Get a list of all the id's i need by:
// grouping by CustID, and then selecting Max ID from each group.
var distinctLatest = (from x in ee.Records
group x by x.CustID into grp
select grp.Max(g => g.id)).ToArray();
// List<Record> result = new List<Record>();
//now we can retrieve individual records using the ID's retrieved above
// foreach (int i in distinctLatest)
// {
// var res = from g in ee.Records where g.id == i select g;
// var arr = res.ToArray();
// result.Add(res.First());
// }
// alternate version of foreach
dgvLatestDistinctRec.DataSource = from g in ee.Records
join i in distinctLatest
on g.id equals i
select g;