我如何最优雅地用聚合SQL将左联接表示为LINQ查询
时间:2020-03-05 18:37:26 来源:igfitidea点击:
SQL:
SELECT u.id, u.name, isnull(MAX(h.dateCol), '1900-01-01') dateColWithDefault FROM universe u LEFT JOIN history h ON u.id=h.id AND h.dateCol<GETDATE()-1 GROUP BY u.Id, u.name
解决方案:
一种## 解决方案,尽管可以将对null值的处理推迟到代码中,但可以是:
DateTime yesterday = DateTime.Now.Date.AddDays(-1);
var collection= from u in db.Universe select new { u.id, u.name, MaxDate =(DateTime?) ( from h in db.History where u.Id == h.Id && h.dateCol < yesterday select h.dateCol ).Max() };
这不会产生完全相同的SQL,但是会提供相同的逻辑结果。将"复杂的" SQL查询转换为LINQ并不总是那么简单。
对于我们来说,这不是一个完整的答案,但是在左侧的连接块上,我们可以使用DefaultIfEmpty运算符,如下所示:
var collection = from u in db.Universe join history in db.History on u.id = history.id into temp from h in temp.DefaultIfEmpty() where h.dateCol < DateTime.Now.Date.AddDays(-1) select u.id, u.name, h.dateCol ?? '1900-01-01'
我还不需要执行任何groupby命令,因此我将其排除在外是为了不使我们误入歧途。还有两件事需要注意。我无法真正加入两个参数,尽管如上所述,有一些方法可以解决这个问题。另外,??运算符可以很好地代替SQL中的isnull。
我们将要使用" join into"构造来创建组查询。
TestContext db = new TestContext(CreateSparqlTripleStore()); var q = from a in db.Album join t in db.Track on a.Name equals t.AlbumName into tracks select new Album{Name = a.Name, Tracks = tracks}; foreach(var album in q){ Console.WriteLine(album.Name); foreach (Track track in album.Tracks) { Console.WriteLine(track.Title); } }