Comments on: It’s better to .Take() https://codejack.com/2020/05/sql-linq-efcore-and-sub-select/ Programming blog focused primarily on .Net and Microsoft Sun, 10 May 2020 02:12:17 +0000 hourly 1 https://wordpress.org/?v=6.9.4 By: Robin Sue https://codejack.com/2020/05/sql-linq-efcore-and-sub-select/#comment-8 Sun, 10 May 2020 02:12:17 +0000 https://jop.rnz.mybluehost.me/website_857cfe54/?p=22#comment-8 In reply to feech. > The goal is to retrieve the single most recent record ComponentStatus and populate LastComponentStatus with that record, not a list. Yes, the code i’ve suggested does exactly that, it caches a one-to-one navigation as LatestComponentStatusId on Component, which allows for fast and easy retrieval with a trivial join but the downside, that you must keep this cached value up-to-date and that it doesn’t work well if there’s a time dependency. > The point of my post… Yeah i’ve got that, quite weird, i agree 🙂

]]>
By: feech https://codejack.com/2020/05/sql-linq-efcore-and-sub-select/#comment-7 Fri, 08 May 2020 15:42:36 +0000 https://jop.rnz.mybluehost.me/website_857cfe54/?p=22#comment-7 In reply to Robin Sue. Hi Robin! The goal is to retrieve the single most recent record ComponentStatus and populate LastComponentStatus with that record, not a list. The point of my post was that even if you try a simple join with a sub-select inside the join to just retrieve 1 record, the translated query is highly inefficient. You actually have to retrieve both records individually and use .Take(). For some reason EFCore changes the entire query structure between .FirstOrDefault() and .Take(1).FirstOrDefault() as I was trying to show. take care, jasen

]]>
By: Robin Sue https://codejack.com/2020/05/sql-linq-efcore-and-sub-select/#comment-6 Fri, 08 May 2020 01:59:22 +0000 https://jop.rnz.mybluehost.me/website_857cfe54/?p=22#comment-6 In reply to feech. I mean, when you use LatestComponentStatus as a navigation property, you can do context.Components.Include(x => x.LatestComponentStatus).ToList(); which results in SELECT [c].[Id], [c].[LatestComponentStatusId], [c0].[Id], [c0].[ComponentId], [c0].[DateChanged], [c0].[Status] FROM [Components] AS [c] LEFT JOIN [ComponentStatus] AS [c0] ON [c].[LatestComponentStatusId] = [c0].[Id] which is as efficient as it gets and populates the LatestComponentStatus automatically, the downside is that everytime you insert, you need to update the LatestComponentStatusId on Component. Thinking about it though, the cs.DateChanged < DateTime.UtcNow part probably means you can have a future status that must not be (yet) selected so this idea just went down the drain 🙂

]]>
By: feech https://codejack.com/2020/05/sql-linq-efcore-and-sub-select/#comment-5 Fri, 08 May 2020 00:06:39 +0000 https://jop.rnz.mybluehost.me/website_857cfe54/?p=22#comment-5 In reply to Robin Sue. Hi Robin — All great catches and mostly a result of my first attempt at trying to transpose code into WordPress. I’ll clean up your catches! Much appreciated. As far as some of your non-syntactical observations: 1) .OrderBy was a replacement for my internal query which wasn’t Id, so yes, OrderByDescending is most accurate for this generic version. Thanks! 2) LastComponentStatus as a native navigation property using a subselect query is completely doable, and works. However, the generated SQL reverts back to the inefficient join that basically blows things up at scale. I had debated for sample purposes pulling it out and just demonstrating via an external ComponentStatus but ultimately left it as a nav property for clarity. Guess I #failed haha. Thanks again for noticing some of the styling and formatting issues. Next post coming next week, I’ll attempt to raise the bar. feech

]]>
By: Robin Sue https://codejack.com/2020/05/sql-linq-efcore-and-sub-select/#comment-4 Thu, 07 May 2020 23:49:41 +0000 https://jop.rnz.mybluehost.me/website_857cfe54/?p=22#comment-4 Interesting problem but also a bit confusing and there are a few errors in the code samples: public DateChanged { get; set; } does not specify a type (DateTime), public in ComponentId { get; set; } misspelled int, .OrderBy(cs=>cs.Id) should likely be OrderByDescending if you’re looking for the latest status, results.forEach(x=>x.component.CurrentComponentStatus = x.componentstatus); forEach should be PascalCase and CurrentComponentStatus should be LatestComponentStatus. Also is LatestComponentStatus a navigation property? It is declared virtual which makes this likely, why not just db.Components.Include(x => x.LatestComponentStatus) then? That will generate a straightforward join. If it is not a navigation property or part of the db model, why is it declared on a db class? Last but not least, it took me way longer than i’d like to admit to realize, that cs.DateChanged<DateTime.UtcNow in the second code sample is not generic code where the right hand side is truncated from view (the UtcNow touches the border of the codebox but there's no scrollbar) but a comparison without whitespace inbetween 😀

]]>