C# 寻找更优雅的LINQ解决方案

C# 寻找更优雅的LINQ解决方案,c#,sql,linq,npgsql,C#,Sql,Linq,Npgsql,我正试图找出一种有效的方法来检索我要查找的数据。我需要按ParentId获取所有最近的子项的列表,以及所有没有子项的父项。我已经创建了一个视觉指南来说明响应应该是什么 在完成所有排序和分页之前,查询需要保持为IQueryable。 LINQ to实体不支持Last和LastOrDefault(如我在使用它们时收到的错误消息所述) 使用First或First或default将返回错误“此方法或操作未实现” 原始数据: ------------------------------- - Id - P

我正试图找出一种有效的方法来检索我要查找的数据。我需要按ParentId获取所有最近的子项的列表,以及所有没有子项的父项。我已经创建了一个视觉指南来说明响应应该是什么

在完成所有排序和分页之前,查询需要保持为IQueryable。 LINQ to实体不支持
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));