C# 寻找更优雅的LINQ解决方案
我正试图找出一种有效的方法来检索我要查找的数据。我需要按ParentId获取所有最近的子项的列表,以及所有没有子项的父项。我已经创建了一个视觉指南来说明响应应该是什么 在完成所有排序和分页之前,查询需要保持为IQueryable。 LINQ to实体不支持C# 寻找更优雅的LINQ解决方案,c#,sql,linq,npgsql,C#,Sql,Linq,Npgsql,我正试图找出一种有效的方法来检索我要查找的数据。我需要按ParentId获取所有最近的子项的列表,以及所有没有子项的父项。我已经创建了一个视觉指南来说明响应应该是什么 在完成所有排序和分页之前,查询需要保持为IQueryable。 LINQ to实体不支持Last和LastOrDefault(如我在使用它们时收到的错误消息所述) 使用First或First或default将返回错误“此方法或操作未实现” 原始数据: ------------------------------- - Id - P
Last
和LastOrDefault
(如我在使用它们时收到的错误消息所述)
使用First
或First或default
将返回错误“此方法或操作未实现
”
原始数据:
-------------------------------
- Id - ParentId - CreatedDate -
-------------------------------
- 1 - - 07/01/2013 -
- 2 - - 07/01/2013 -
- 3 - - 07/01/2013 -
- 4 - 1 - 07/02/2013 -
- 5 - 2 - 07/03/2013 -
- 6 - 2 - 07/04/2013 -
- 7 - 1 - 07/05/2013 -
-------------------------------
查询返回的数据
-------------------------------
- Id - ParentId - CreatedDate -
-------------------------------
- 3 - - 07/01/2013 -
- 6 - 2 - 07/04/2013 -
- 7 - 1 - 07/05/2013 -
-------------------------------
目前,我的LINQ查询如下所示:
// Retrieves parent records with NO children.
var q1 = myTable
.Where(x => x.ParentId == null)
.Except(myTable
.Where(x => myTable
.Any(c => (c.ParentId == x.Id))));
// Retrieves most recent child records for each parentId
var q2 =
(from a in myTable
join b in
(myTable.Where(a => a.ParentId != null)
.GroupBy(a => a.ParentId)
.Select(b => new { ParentId = b.Key, CreatedDate = b.Max(t => t.CreatedDate) }))
on a.ParentId equals b.ParentId
where a.CreatedDate == b.CreatedDate
select a);
q1 = q1.Union(q2);
后端将Npgsql2与PostgreSQL一起使用。我正在为这个问题寻找一个更优雅的解决方案。我对LINQ非常陌生,希望对其进行优化
排序代码(松散,但jTable返回以下字符串):
分页代码:
var result = pageSize > 0
? q1.Skip(startIndex).Take(pageSize).ToList()
: q1.ToList();
使用分组:
模拟数据:
public class Entry {
public int Id { get; set; }
public int? ParentId { get; set; }
public DateTime Date { get; set; }
};
var list = new List<Entry> {
new Entry{ Id = 1, ParentId = null, Date = new DateTime(2013, 7, 1) },
new Entry{ Id = 2, ParentId = null, Date = new DateTime(2013, 7, 1) },
new Entry{ Id = 3, ParentId = null, Date = new DateTime(2013, 7, 1) },
new Entry{ Id = 4, ParentId = 1, Date = new DateTime(2013, 7, 2) },
new Entry{ Id = 5, ParentId = 2, Date = new DateTime(2013, 7, 3) },
new Entry{ Id = 6, ParentId = 2, Date = new DateTime(2013, 7, 4) },
new Entry{ Id = 7, ParentId = 1, Date = new DateTime(2013, 7, 5) }
};
LinqPad结果:
Id ParentId Date
3 null 01.07.2013 0:00:00
6 2 04.07.2013 0:00:00
7 1 05.07.2013 0:00:00
我可以提出一个不同的查询,仍然分为两个阶段
var firstQuery = myTable.Select(p => new { p.ID, ParentID = p.ParentID ?? p.ID, p.CreatedDate })
.GroupBy( p => p.ParentID).Select( q => new
{
el = q.OrderByDescending( k => k.CreatedDate).Take(1)
}).SelectMany(t => t.el);
var result = dc.TabellaId_ParentId.Where(p => test.Select(q => q.ID).Contains(p.ID));
在我的脑海里,我想不出有什么办法能让它变得更好。我认为,如果您可以将这一点放到一个查询中,那么SQL将不会更加优化。您已经拥有的两个查询都是相当高级的LINQ,因此您可以为能够让它们像现在这样工作而感到自豪。:)您是想让查询运行得更快,还是想将其重构为一个IQueryable?在速度方面,我认为最好是查看并从中进行选择。在查询方面,我认为您目前如何进行拆分是合乎逻辑的:-)可能是一个驱动因素问题,我在Oracle中有过大量的查询,在此之前,我有非常好的linq。如果你不介意一个非常愚蠢的问题——在你的例子中,你的
Id
似乎随着日期的增加而增加——那么,在你的完整数据集中是这样的,还是仅仅是你在示例数据中添加的?如果是这样的话,您根本不需要查看date列……如果您使用的是Npgsql,那么您不需要使用LINQ to SQL,它是另一个提供程序(请更新您的标记和问题标题)。查询生成是提供商的责任,似乎是您问题的根源。感谢您的回复。使用Last
、LastOrDefault
、First
或FirstOrDefault
在IQueryable
中时将无法与我的提供商一起使用。我需要将查询保持在IQueryable
中,直到完成所有排序和分页,以减少检索到的对象数量。
Id ParentId Date
3 null 01.07.2013 0:00:00
6 2 04.07.2013 0:00:00
7 1 05.07.2013 0:00:00
var firstQuery = myTable.Select(p => new { p.ID, ParentID = p.ParentID ?? p.ID, p.CreatedDate })
.GroupBy( p => p.ParentID).Select( q => new
{
el = q.OrderByDescending( k => k.CreatedDate).Take(1)
}).SelectMany(t => t.el);
var result = dc.TabellaId_ParentId.Where(p => test.Select(q => q.ID).Contains(p.ID));